From 7f363830eb6275ff0c5be11acac639fb19509c74 Mon Sep 17 00:00:00 2001 From: Rikki Schulte Date: Sat, 11 Apr 2020 08:38:22 -0400 Subject: [PATCH 1/2] fix: handle all schema and LSP errors --- .../src/GraphQLLanguageService.ts | 7 +- .../src/startServer.ts | 124 ++++++++++-------- 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts b/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts index a2904c9f815..3ee63febf48 100644 --- a/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts +++ b/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts @@ -208,9 +208,10 @@ export class GraphQLLanguageService { } /* eslint-enable no-implicit-coercion */ } - const schema = await this._graphQLCache - .getSchema(projectName, queryHasExtensions) - .catch(() => null); + const schema = await this._graphQLCache.getSchema( + projectName, + queryHasExtensions, + ); if (!schema) { return []; diff --git a/packages/graphql-language-service-server/src/startServer.ts b/packages/graphql-language-service-server/src/startServer.ts index 1a4016d129d..7363b9bda70 100644 --- a/packages/graphql-language-service-server/src/startServer.ts +++ b/packages/graphql-language-service-server/src/startServer.ts @@ -72,61 +72,79 @@ export default async function startServer(options: Options): Promise { if (options && options.method) { let reader; let writer; - switch (options.method) { - case 'socket': - // For socket connection, the message connection needs to be - // established before the server socket starts listening. - // Do that, and return at the end of this block. - if (!options.port) { - process.stderr.write( - '--port is required to establish socket connection.', - ); - process.exit(1); - } - - const port = options.port; - const socket = net - .createServer(client => { - client.setEncoding('utf8'); - reader = new SocketMessageReader(client); - writer = new SocketMessageWriter(client); - client.on('end', () => { - socket.close(); - process.exit(0); - }); - const connection = createMessageConnection(reader, writer, logger); - addHandlers( - connection, - logger, - options.configDir, - options?.extensions ?? [], - options.config, + let connection; + try { + switch (options.method) { + case 'socket': + // For socket connection, the message connection needs to be + // established before the server socket starts listening. + // Do that, and return at the end of this block. + if (!options.port) { + process.stderr.write( + '--port is required to establish socket connection.', ); - connection.listen(); - }) - .listen(port); - return; - case 'stream': - reader = new StreamMessageReader(process.stdin); - writer = new StreamMessageWriter(process.stdout); - break; - case 'node': - default: - reader = new IPCMessageReader(process); - writer = new IPCMessageWriter(process); - break; + process.exit(1); + } + + const port = options.port; + const socket = net + .createServer(client => { + client.setEncoding('utf8'); + reader = new SocketMessageReader(client); + writer = new SocketMessageWriter(client); + client.on('end', () => { + socket.close(); + process.exit(0); + }); + const connection = createMessageConnection( + reader, + writer, + logger, + ); + addHandlers( + connection, + logger, + options.configDir, + options?.extensions ?? [], + options.config, + ); + connection.listen(); + }) + .listen(port); + return; + case 'stream': + reader = new StreamMessageReader(process.stdin); + writer = new StreamMessageWriter(process.stdout); + break; + case 'node': + default: + reader = new IPCMessageReader(process); + writer = new IPCMessageWriter(process); + break; + } + connection = createMessageConnection(reader, writer, logger); + } catch (err) { + logger.error('There was an error initializing the server connection'); + logger.error(err); + process.exit(1); + } + if (connection) { + try { + addHandlers( + connection, + logger, + options.configDir, + options?.extensions ?? [], + options.config, + options.parser, + options.fileExtensions, + ); + connection.listen(); + } catch (err) { + logger.error('There was a Graphql LSP handler exception:'); + logger.error(err); + } } - const connection = createMessageConnection(reader, writer, logger); - addHandlers( - connection, - logger, - options.configDir, - options?.extensions ?? [], - options.config, - options.parser, - options.fileExtensions, - ); - connection.listen(); } } From 1112f15bd471eb85adcd9d19ef1f72a70bc8c6ca Mon Sep 17 00:00:00 2001 From: Rikki Schulte Date: Sat, 11 Apr 2020 11:17:49 -0400 Subject: [PATCH 2/2] fix: fix cli, improve error handling --- .../src/GraphQLLanguageService.ts | 3 + .../src/startServer.ts | 165 ++++++++++-------- packages/graphql-language-service/src/cli.ts | 1 + .../graphql-language-service/tsconfig.json | 3 +- 4 files changed, 95 insertions(+), 77 deletions(-) diff --git a/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts b/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts index 3ee63febf48..8221a79a9e6 100644 --- a/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts +++ b/packages/graphql-language-service-interface/src/GraphQLLanguageService.ts @@ -125,6 +125,9 @@ export class GraphQLLanguageService { // schema/fragment definitions, even the project configuration. let queryHasExtensions = false; const projectConfig = this.getConfigForURI(uri); + if (!projectConfig) { + return []; + } const { schema: schemaPath, name: projectName, extensions } = projectConfig; try { diff --git a/packages/graphql-language-service-server/src/startServer.ts b/packages/graphql-language-service-server/src/startServer.ts index 7363b9bda70..325cae2deed 100644 --- a/packages/graphql-language-service-server/src/startServer.ts +++ b/packages/graphql-language-service-server/src/startServer.ts @@ -44,10 +44,10 @@ import { import { Logger } from './Logger'; import { parseDocument } from './parseDocument'; -type Options = { - // port for the LSP server to run on +export type ServerOptions = { + // port for the LSP server to run on. required if using method socket port?: number; - // socket, streams, or node (ipc). if socket, port is required + // socket, streams, or node (ipc) method?: 'socket' | 'stream' | 'node'; // the directory where graphql-config is found configDir?: string; @@ -58,96 +58,109 @@ type Options = { config?: GraphQLConfig; parser?: typeof parseDocument; }; -('graphql-language-service-types'); /** * startServer - initialize LSP server with options * - * @param options {Options} server initialization methods + * @param options {ServerOptions} server initialization methods * @returns {Promise} */ -export default async function startServer(options: Options): Promise { +export default async function startServer( + options: ServerOptions, +): Promise { const logger = new Logger(); - if (options && options.method) { let reader; let writer; - let connection; - try { - switch (options.method) { - case 'socket': - // For socket connection, the message connection needs to be - // established before the server socket starts listening. - // Do that, and return at the end of this block. - if (!options.port) { - process.stderr.write( - '--port is required to establish socket connection.', - ); - process.exit(1); - } + switch (options.method) { + case 'socket': + // For socket connection, the message connection needs to be + // established before the server socket starts listening. + // Do that, and return at the end of this block. + if (!options.port) { + process.stderr.write( + '--port is required to establish socket connection.', + ); + process.exit(1); + } - const port = options.port; - const socket = net - .createServer(client => { - client.setEncoding('utf8'); - reader = new SocketMessageReader(client); - writer = new SocketMessageWriter(client); - client.on('end', () => { - socket.close(); - process.exit(0); - }); - const connection = createMessageConnection( - reader, - writer, - logger, - ); - addHandlers( - connection, - logger, - options.configDir, - options?.extensions ?? [], - options.config, - ); - connection.listen(); - }) - .listen(port); - return; - case 'stream': - reader = new StreamMessageReader(process.stdin); - writer = new StreamMessageWriter(process.stdout); - break; - case 'node': - default: - reader = new IPCMessageReader(process); - writer = new IPCMessageWriter(process); - break; - } - connection = createMessageConnection(reader, writer, logger); + const port = options.port; + const socket = net + .createServer(client => { + client.setEncoding('utf8'); + reader = new SocketMessageReader(client); + writer = new SocketMessageWriter(client); + client.on('end', () => { + socket.close(); + process.exit(0); + }); + const serverWithHandlers = initializeHandlers({ + reader, + writer, + logger, + options, + }); + + serverWithHandlers.listen(); + }) + .listen(port); + return; + case 'stream': + reader = new StreamMessageReader(process.stdin); + writer = new StreamMessageWriter(process.stdout); + break; + case 'node': + default: + reader = new IPCMessageReader(process); + writer = new IPCMessageWriter(process); + break; + } + + try { + const serverWithHandlers = initializeHandlers({ + reader, + writer, + logger, + options, + }); + return serverWithHandlers.listen(); } catch (err) { - logger.error('There was an error initializing the server connection'); + logger.error('There was a Graphql LSP handler exception:'); logger.error(err); - process.exit(1); - } - if (connection) { - try { - addHandlers( - connection, - logger, - options.configDir, - options?.extensions ?? [], - options.config, - options.parser, - options.fileExtensions, - ); - connection.listen(); - } catch (err) { - logger.error('There was a Graphql LSP handler exception:'); - logger.error(err); - } } } } +function initializeHandlers({ + reader, + writer, + logger, + options = {}, +}: { + reader: SocketMessageReader | StreamMessageReader | IPCMessageReader; + writer: SocketMessageWriter | StreamMessageWriter | IPCMessageWriter; + logger: Logger; + options: ServerOptions; +}): MessageConnection { + try { + const connection = createMessageConnection(reader, writer, logger); + addHandlers( + connection, + logger, + options.configDir, + options?.extensions || [], + options.config, + options.parser, + options.fileExtensions, + ); + return connection; + } catch (err) { + logger.error('There was an error initializing the server connection'); + logger.error(err); + process.exit(1); + } +} + function addHandlers( connection: MessageConnection, logger: Logger, diff --git a/packages/graphql-language-service/src/cli.ts b/packages/graphql-language-service/src/cli.ts index 3e2501628b1..dbb14569111 100644 --- a/packages/graphql-language-service/src/cli.ts +++ b/packages/graphql-language-service/src/cli.ts @@ -83,6 +83,7 @@ const { argv } = yargs 'Can be one of: stream, node, socket.\n' + 'Will default to use a node IPC channel for communication.\n', type: 'string', + default: 'node', }) .option('p', { alias: 'port', diff --git a/packages/graphql-language-service/tsconfig.json b/packages/graphql-language-service/tsconfig.json index fbcb4047799..480002d421b 100644 --- a/packages/graphql-language-service/tsconfig.json +++ b/packages/graphql-language-service/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "composite": true, "rootDir": "./src", - "outDir": "./dist" + "outDir": "./dist", + "target": "ES2017" }, "references": [ {