From 4ce47bb25077de87465cd54d4aa85cf3c8954d77 Mon Sep 17 00:00:00 2001 From: Naman Kumar Date: Sun, 30 Aug 2020 20:48:42 +0530 Subject: [PATCH] [WIP] Integrate graphql-js experimental parser --- packages/codemirror-graphql/src/mode.js | 20 ++--- .../src/GraphqlParser.ts | 83 +++++++++++++++++++ .../src/index.ts | 2 + 3 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 packages/graphql-language-service-parser/src/GraphqlParser.ts diff --git a/packages/codemirror-graphql/src/mode.js b/packages/codemirror-graphql/src/mode.js index 23dad24a13d..b9688341648 100644 --- a/packages/codemirror-graphql/src/mode.js +++ b/packages/codemirror-graphql/src/mode.js @@ -8,12 +8,7 @@ */ import CodeMirror from 'codemirror'; -import { - LexRules, - ParseRules, - isIgnored, - onlineParser, -} from 'graphql-language-service-parser'; +import { GraphqlParser } from 'graphql-language-service-parser'; /** * The GraphQL mode is defined as a tokenizer along with a list of rules, each @@ -36,16 +31,11 @@ import { * 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: config.tabSize }, - }); + const parser = new GraphqlParser({ tabSize: config.tabSize }); return { config, - startState: parser.startState, + startState: GraphqlParser.startState, token: parser.token, indent, electricInput: /^\s*[})\]]/, @@ -55,6 +45,7 @@ CodeMirror.defineMode('graphql', config => { pairs: '()[]{}""', explode: '()[]{}', }, + copyState: GraphqlParser.copyState, }; }); @@ -65,7 +56,6 @@ function indent(state, textAfter) { const level = !levels || levels.length === 0 ? state.indentLevel - : levels[levels.length - 1] - - (this.electricInput.test(textAfter) ? 1 : 0); + : levels[levels.length - 1] - (this.electricInput.test(textAfter) ? 1 : 0); return level * this.config.indentUnit; } diff --git a/packages/graphql-language-service-parser/src/GraphqlParser.ts b/packages/graphql-language-service-parser/src/GraphqlParser.ts new file mode 100644 index 00000000000..50c14396aaa --- /dev/null +++ b/packages/graphql-language-service-parser/src/GraphqlParser.ts @@ -0,0 +1,83 @@ +import { OnlineParser, OnlineParserState, TokenKind } from 'graphql/experimentalOnlineParser'; +import CharacterStream from './CharacterStream'; +import { isIgnored, LexRules } from './Rules'; +const styles = require('./styles.json'); + +export interface State extends ParserState { + name: string | null; + type: string | null; + prevState: State | null; +} + +export default class GraphqlParser { + config: any; + + constructor(config = {}) { + this.config = config; + } + + static startState = (): State => { + const state: any = OnlineParser.startState(); + state.prevState = null; + + return state; + }; + + static copyState = (state: State): State => { + const newState: any = OnlineParser.copyState(state); + newState.prevState = state.prevState; + + return newState as State; + }; + + token(stream: CharacterStream, state: State): string { + const prevState = GraphqlParser.copyState(state); + + if (stream.eatWhile(isIgnored)) { + return 'ws'; + } + + if (stream.eol()) { + return 'invalidchar'; + } + + const source = ((stream.match(/.*/, false) as Array) || [])[0] || ''; + const parserState = OnlineParser.copyState(state); + const parser = new OnlineParser(source, parserState, this.config); + + const token = parser.parseToken(); + + if (token.kind !== 'Invalid' && token.value) { + Object.assign(state, parserState); + if (token.kind === TokenKind.PUNCTUATION) { + stream.match(LexRules.Punctuation); + } else { + stream.match(token.value); + } + } else { + stream.skipToEnd(); + } + + state.prevState = prevState; + + return styles[token.tokenName] || styles[token.ruleName] || styles[token.kind] || ''; + } +} + +export type ContextToken = { + start: number; + end: number; + string: string; + state: State; + style: string; +}; + +export type ContextTokenForCodeMirror = { + start: number; + end: number; + string: string; + type: string | null; + state: State; +}; + +export type ContextTokenUnion = ContextToken | ContextTokenForCodeMirror; diff --git a/packages/graphql-language-service-parser/src/index.ts b/packages/graphql-language-service-parser/src/index.ts index 13c205c5571..d2ec818e7dd 100644 --- a/packages/graphql-language-service-parser/src/index.ts +++ b/packages/graphql-language-service-parser/src/index.ts @@ -15,4 +15,6 @@ export { butNot, list, opt, p, t } from './RuleHelpers'; export { default as onlineParser } from './onlineParser'; +export { default as GraphqlParser } from './GraphqlParser'; + export * from './types';