diff --git a/components/graphql/queryeditor.vue b/components/graphql/queryeditor.vue index 7a4e90c65..56fe6bc35 100644 --- a/components/graphql/queryeditor.vue +++ b/components/graphql/queryeditor.vue @@ -7,7 +7,9 @@ const DEFAULT_THEME = "twilight"; import ace from "ace-builds"; import * as gql from "graphql"; +import { getAutocompleteSuggestions } from "graphql-language-service-interface"; import "ace-builds/webpack-resolver"; +import "ace-builds/src-noconflict/ext-language_tools"; import debounce from "../../functions/utils/debounce"; export default { @@ -46,10 +48,10 @@ export default { } }, theme() { - this.editor.setTheme("ace/theme/" + this.defineTheme()); + this.editor.setTheme(`ace/theme/${this.defineTheme()}`); }, lang(value) { - this.editor.getSession().setMode("ace/mode/" + value); + this.editor.getSession().setMode(`ace/mode/${value}`); }, options(value) { this.editor.setOptions(value); @@ -57,12 +59,48 @@ export default { }, mounted() { + let langTools = ace.require("ace/ext/language_tools"); + const editor = ace.edit(this.$refs.editor, { - theme: "ace/theme/" + this.defineTheme(), - mode: "ace/mode/" + this.lang, + theme: `ace/theme/${this.defineTheme()}`, + mode: `ace/mode/${this.lang}`, + enableBasicAutocompletion: true, + enableLiveAutocompletion: true, ...this.options }); + const completer = { + getCompletions: ( + editor, + _session, + { row, column }, + _prefix, + callback + ) => { + if (this.validationSchema) { + const completions = getAutocompleteSuggestions( + this.validationSchema, + editor.getValue(), + { line: row, character: column } + ); + + callback( + null, + completions.map(({ label, detail }) => ({ + name: label, + value: label, + score: 1.0, + meta: detail + })) + ); + } else { + callback(null, []); + } + } + }; + + langTools.setCompleters([completer]); + if (this.value) editor.setValue(this.value, 1); this.editor = editor; @@ -101,14 +139,14 @@ export default { if (this.validationSchema) { this.editor.session.setAnnotations( - gql.validate(this.validationSchema, doc).map(err => { - return { - row: err.locations[0].line - 1, - column: err.locations[0].column - 1, - text: err.message, + gql + .validate(this.validationSchema, doc) + .map(({ locations, message }) => ({ + row: locations[0].line - 1, + column: locations[0].column - 1, + text: message, type: "error" - }; - }) + })) ); } } catch (e) { diff --git a/package-lock.json b/package-lock.json index 161faee72..85bbc7eaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3822,6 +3822,27 @@ "sha.js": "^2.4.8" } }, + "cross-fetch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz", + "integrity": "sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=", + "requires": { + "node-fetch": "2.1.2", + "whatwg-fetch": "2.0.4" + }, + "dependencies": { + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" + }, + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + } + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -5589,6 +5610,79 @@ "iterall": "^1.2.2" } }, + "graphql-config": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-2.2.1.tgz", + "integrity": "sha512-U8+1IAhw9m6WkZRRcyj8ZarK96R6lQBQ0an4lp76Ps9FyhOXENC5YQOxOFGm5CxPrX2rD0g3Je4zG5xdNJjwzQ==", + "requires": { + "graphql-import": "^0.7.1", + "graphql-request": "^1.5.0", + "js-yaml": "^3.10.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.4" + } + }, + "graphql-import": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/graphql-import/-/graphql-import-0.7.1.tgz", + "integrity": "sha512-YpwpaPjRUVlw2SN3OPljpWbVRWAhMAyfSba5U47qGMOSsPLi2gYeJtngGpymjm9nk57RFWEpjqwh4+dpYuFAPw==", + "requires": { + "lodash": "^4.17.4", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + } + } + }, + "graphql-language-service-interface": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/graphql-language-service-interface/-/graphql-language-service-interface-2.3.3.tgz", + "integrity": "sha512-SMUbbiHbD19ffyDrucR+vwyaKYhDcTgbBFDJu9Z4TBa5XaksmyiurB3f+pWlIkuFvogBvW3JDiiJJlUW7awivg==", + "requires": { + "graphql-config": "2.2.1", + "graphql-language-service-parser": "^1.5.2", + "graphql-language-service-types": "^1.5.2", + "graphql-language-service-utils": "^2.3.3" + } + }, + "graphql-language-service-parser": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/graphql-language-service-parser/-/graphql-language-service-parser-1.5.2.tgz", + "integrity": "sha512-kModfvwX5XiT+tYRhh8d6X+rb5Zq9zFQVdcoVlQJvoIW7U6SkxUAeO5Ei9OI3KOMH5r8wyfmXflBZ+xUbJySJw==", + "requires": { + "graphql-config": "2.2.1", + "graphql-language-service-types": "^1.5.2" + } + }, + "graphql-language-service-types": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/graphql-language-service-types/-/graphql-language-service-types-1.5.2.tgz", + "integrity": "sha512-WOFHBZX1K41svohPTmhOcKg+zz27d6ULFuZ8mzkiJ9nIpGKueAPyh7/xR0VZNBUAfDzTCbE6wQZxsPl5Kvd7IA==", + "requires": { + "graphql-config": "2.2.1" + } + }, + "graphql-language-service-utils": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/graphql-language-service-utils/-/graphql-language-service-utils-2.3.3.tgz", + "integrity": "sha512-uHLdIbQpKkE1V2WA12DRMXrUZpPD3ZKPOuH3MHlNg+j9AEe1y83chA4yP5DQqR+ARdMpefz4FJHvEjQr9alXYw==", + "requires": { + "graphql-config": "2.2.1", + "graphql-language-service-types": "^1.5.2" + } + }, + "graphql-request": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-1.8.2.tgz", + "integrity": "sha512-dDX2M+VMsxXFCmUX0Vo0TopIZIX4ggzOtiCsThgtrKR4niiaagsGTDIHj3fsOMFETpa064vzovI+4YV4QnMbcg==", + "requires": { + "cross-fetch": "2.2.2" + } + }, "grpc": { "version": "1.24.2", "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.24.2.tgz", diff --git a/package.json b/package.json index 55bd32240..6a887e1c1 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "ace-builds": "^1.4.8", "firebase": "^7.9.1", "graphql": "^14.6.0", + "graphql-language-service-interface": "^2.3.3", "nuxt": "^2.11.0", "nuxt-i18n": "^6.5.0", "v-tooltip": "^2.0.3",