graphql-language-service
Advanced tools
Comparing version
{ | ||
"name": "graphql-language-service", | ||
"repository": "https://github.com/graphql/graphql-language-service", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "An interface for building GraphQL language services for IDEs", | ||
@@ -42,13 +42,14 @@ "contributors": [ | ||
"babel-polyfill": "6.16.0", | ||
"fb-watchman": "^2.0.0", | ||
"graphql": "^0.9.2", | ||
"graphql-language-service-config": "0.0.7", | ||
"graphql-language-service-interface": "0.0.7", | ||
"graphql-language-service-server": "0.0.10", | ||
"graphql-language-service-parser": "0.0.6", | ||
"graphql-language-service-server": "0.0.11", | ||
"graphql-language-service-types": "0.0.12", | ||
"graphql-language-service-utils": "0.0.6", | ||
"yargs": "^7.0.1", | ||
"graphql-language-service-types": "0.0.12", | ||
"graphql-language-service-config": "0.0.7", | ||
"graphql-language-service-parser": "0.0.6", | ||
"fb-watchman": "^2.0.0", | ||
"nullthrows": "^1.0.0", | ||
"vscode-jsonrpc": "^3.2.0" | ||
"vscode-jsonrpc": "^3.2.0", | ||
"vscode-languageserver": "^3.2.0", | ||
"yargs": "^7.0.1" | ||
}, | ||
@@ -55,0 +56,0 @@ "devDependencies": { |
@@ -6,17 +6,11 @@ 'use strict'; | ||
}); | ||
exports.handleDidOpenOrSaveNotification = handleDidOpenOrSaveNotification; | ||
exports.handleDidChangeNotification = handleDidChangeNotification; | ||
exports.handleDidCloseNotification = handleDidCloseNotification; | ||
exports.handleInitializeRequest = handleInitializeRequest; | ||
exports.handleCompletionRequest = handleCompletionRequest; | ||
exports.handleDefinitionRequest = handleDefinitionRequest; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /** | ||
* Copyright (c) Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
*/ | ||
var _vscodeLanguageserver = require('vscode-languageserver'); | ||
exports.processIPCNotificationMessage = processIPCNotificationMessage; | ||
exports.processIPCRequestMessage = processIPCRequestMessage; | ||
exports.processStreamMessage = processStreamMessage; | ||
var _graphqlLanguageServiceConfig = require('graphql-language-service-config'); | ||
@@ -32,2 +26,4 @@ | ||
var _vscodeJsonrpc = require('vscode-jsonrpc'); | ||
var _GraphQLCache = require('./GraphQLCache'); | ||
@@ -37,17 +33,12 @@ | ||
// Response message error codes | ||
var ERROR_CODES = { | ||
PARSE_ERROR: -32700, | ||
INVALID_REQUEST: -32600, | ||
METHOD_NOT_FOUND: -32601, | ||
INVALID_PARAMS: -32602, | ||
INTERNAL_ERROR: -32603, | ||
SERVER_ERROR_START: -32099, | ||
SERVER_ERROR_END: -32000, | ||
SERVER_NOT_INITIALIZED: -32002, | ||
UNKNOWN_ERROR_CODE: -32001 | ||
}; | ||
/** | ||
* Copyright (c) Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
*/ | ||
var REQUEST_IDS_IN_PROGRESS = []; | ||
var graphQLCache = void 0; | ||
@@ -57,26 +48,17 @@ var languageService = void 0; | ||
function processIPCNotificationMessage(message, writer) { | ||
var method, response, textDocument, diagnostics, uri, text, cachedDocument, contentChanges, documentUri; | ||
return regeneratorRuntime.async(function processIPCNotificationMessage$(_context) { | ||
function handleDidOpenOrSaveNotification(params) { | ||
var textDocument, uri, text, cachedDocument, diagnostics; | ||
return regeneratorRuntime.async(function handleDidOpenOrSaveNotification$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
method = message.method; | ||
response = void 0; | ||
textDocument = void 0; | ||
diagnostics = void 0; | ||
_context.t0 = method; | ||
_context.next = _context.t0 === 'textDocument/didOpen' ? 7 : _context.t0 === 'textDocument/didSave' ? 7 : _context.t0 === 'textDocument/didChange' ? 19 : _context.t0 === 'textDocument/didClose' ? 31 : _context.t0 === 'exit' ? 36 : 38; | ||
break; | ||
case 7: | ||
if (!(!message.params || !message.params.textDocument)) { | ||
_context.next = 9; | ||
if (!(!params || !params.textDocument)) { | ||
_context.next = 2; | ||
break; | ||
} | ||
return _context.abrupt('return'); | ||
throw new Error('`textDocument` argument is required.'); | ||
case 9: | ||
textDocument = message.params.textDocument; | ||
case 2: | ||
textDocument = params.textDocument; | ||
uri = textDocument.uri; | ||
@@ -100,72 +82,61 @@ text = textDocument.text; | ||
_context.next = 15; | ||
_context.next = 8; | ||
return regeneratorRuntime.awrap(provideDiagnosticsMessage(text, uri)); | ||
case 15: | ||
case 8: | ||
diagnostics = _context.sent; | ||
return _context.abrupt('return', { uri: uri, diagnostics: diagnostics }); | ||
response = convertToRpcMessage({ | ||
method: 'textDocument/publishDiagnostics', | ||
params: { uri: uri, diagnostics: diagnostics } | ||
}); | ||
sendMessageIPC(response, writer); | ||
return _context.abrupt('break', 38); | ||
case 10: | ||
case 'end': | ||
return _context.stop(); | ||
} | ||
} | ||
}, null, this); | ||
} | ||
case 19: | ||
if (!(!message.params || !message.params.textDocument || !message.params.contentChanges)) { | ||
_context.next = 21; | ||
function handleDidChangeNotification(params) { | ||
var textDocument, contentChanges, documentUri, cachedDocument, diagnostics; | ||
return regeneratorRuntime.async(function handleDidChangeNotification$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
if (!(!params || !params.textDocument || !params.contentChanges)) { | ||
_context2.next = 2; | ||
break; | ||
} | ||
return _context.abrupt('return'); | ||
throw new Error('`textDocument` and `contentChanges` arguments are required.'); | ||
case 21: | ||
case 2: | ||
textDocument = params.textDocument; | ||
contentChanges = params.contentChanges; | ||
textDocument = message.params.textDocument; | ||
contentChanges = message.params.contentChanges; | ||
// As `contentChanges` is an array and we just want the | ||
// latest update to the text, grab the last entry from the array. | ||
documentUri = textDocument.uri || message.params.uri; | ||
documentUri = textDocument.uri || params.uri; | ||
invalidateCache(textDocument, documentUri, contentChanges[contentChanges.length - 1]); | ||
// Send the diagnostics onChange as well | ||
_context.next = 27; | ||
return regeneratorRuntime.awrap(provideDiagnosticsMessage(textDocumentCache.get(documentUri), documentUri)); | ||
cachedDocument = textDocumentCache.get(documentUri); | ||
case 27: | ||
diagnostics = _context.sent; | ||
response = convertToRpcMessage({ | ||
method: 'textDocument/publishDiagnostics', | ||
params: { documentUri: documentUri, diagnostics: diagnostics } | ||
}); | ||
sendMessageIPC(response, writer); | ||
return _context.abrupt('break', 38); | ||
case 31: | ||
if (!(!message.params || !message.params.textDocument)) { | ||
_context.next = 33; | ||
if (cachedDocument) { | ||
_context2.next = 9; | ||
break; | ||
} | ||
return _context.abrupt('return'); | ||
return _context2.abrupt('return'); | ||
case 33: | ||
textDocument = message.params.textDocument; | ||
case 9: | ||
_context2.next = 11; | ||
return regeneratorRuntime.awrap(provideDiagnosticsMessage(cachedDocument.content.text, documentUri)); | ||
if (textDocumentCache.has(textDocument.uri)) { | ||
textDocumentCache.delete(textDocument.uri); | ||
} | ||
return _context.abrupt('break', 38); | ||
case 11: | ||
diagnostics = _context2.sent; | ||
return _context2.abrupt('return', { documentUri: documentUri, diagnostics: diagnostics }); | ||
case 36: | ||
process.exit(0); | ||
return _context.abrupt('break', 38); | ||
case 38: | ||
case 13: | ||
case 'end': | ||
return _context.stop(); | ||
return _context2.stop(); | ||
} | ||
@@ -176,156 +147,106 @@ } | ||
function processIPCRequestMessage(message, configDir, writer) { | ||
var method, response, textDocument, cachedDocument, query, result, serverCapabilities, position, pos, formatted, requestIDToCancel, index; | ||
return regeneratorRuntime.async(function processIPCRequestMessage$(_context2) { | ||
function handleDidCloseNotification(params) { | ||
var textDocument; | ||
return regeneratorRuntime.async(function handleDidCloseNotification$(_context3) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
method = message.method; | ||
response = void 0; | ||
textDocument = void 0; | ||
cachedDocument = void 0; | ||
query = void 0; | ||
result = void 0; | ||
_context2.t0 = method; | ||
_context2.next = _context2.t0 === 'initialize' ? 9 : _context2.t0 === 'textDocument/completion' ? 17 : _context2.t0 === 'textDocument/definition' ? 30 : _context2.t0 === '$/cancelRequest' ? 44 : _context2.t0 === 'shutdown' ? 50 : 51; | ||
break; | ||
case 9: | ||
if (!(!message.params || !message.params.rootPath)) { | ||
_context2.next = 11; | ||
if (!(!params || !params.textDocument)) { | ||
_context3.next = 2; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
throw new Error('`textDocument` is required.'); | ||
case 11: | ||
_context2.next = 13; | ||
return regeneratorRuntime.awrap(initialize(configDir ? configDir.trim() : message.params.rootPath)); | ||
case 2: | ||
textDocument = params.textDocument; | ||
case 13: | ||
serverCapabilities = _context2.sent; | ||
if (serverCapabilities === null) { | ||
response = convertToRpcMessage({ | ||
id: '-1', | ||
error: { | ||
code: ERROR_CODES.SERVER_NOT_INITIALIZED, | ||
message: '.graphqlrc not found' | ||
} | ||
}); | ||
} else { | ||
response = convertToRpcMessage({ | ||
id: message.id, | ||
result: serverCapabilities | ||
}); | ||
if (textDocumentCache.has(textDocument.uri)) { | ||
textDocumentCache.delete(textDocument.uri); | ||
} | ||
sendMessageIPC(response, writer); | ||
return _context2.abrupt('break', 51); | ||
case 17: | ||
if (!(!message.params || !message.params.textDocument || !message.params.position)) { | ||
_context2.next = 19; | ||
case 4: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
}, null, this); | ||
} | ||
function handleInitializeRequest(params, token, configDir) { | ||
var serverCapabilities; | ||
return regeneratorRuntime.async(function handleInitializeRequest$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
if (!(!params || !params.rootPath)) { | ||
_context4.next = 2; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
throw new Error('`rootPath` argument is required.'); | ||
case 19: | ||
textDocument = message.params.textDocument; | ||
position = message.params.position; | ||
case 2: | ||
_context4.next = 4; | ||
return regeneratorRuntime.awrap(initialize(configDir ? configDir.trim() : params.rootPath)); | ||
case 4: | ||
serverCapabilities = _context4.sent; | ||
cachedDocument = getCachedDocument(textDocument.uri); | ||
if (cachedDocument) { | ||
_context2.next = 24; | ||
if (serverCapabilities) { | ||
_context4.next = 7; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
throw new Error('GraphQL Language Server is not initialized.'); | ||
case 24: | ||
case 7: | ||
return _context4.abrupt('return', serverCapabilities); | ||
query = cachedDocument.content.text; | ||
_context2.next = 27; | ||
return regeneratorRuntime.awrap(languageService.getAutocompleteSuggestions(query, position, textDocument.uri)); | ||
case 8: | ||
case 'end': | ||
return _context4.stop(); | ||
} | ||
} | ||
}, null, this); | ||
} | ||
case 27: | ||
result = _context2.sent; | ||
sendMessageIPC(convertToRpcMessage({ | ||
id: message.id, | ||
result: { items: result, isCompleted: true } | ||
}), writer); | ||
return _context2.abrupt('break', 51); | ||
case 30: | ||
if (!(!message.params || !message.params.textDocument || !message.params.position)) { | ||
_context2.next = 32; | ||
function handleCompletionRequest(params, token) { | ||
var textDocument, position, cachedDocument, query, result; | ||
return regeneratorRuntime.async(function handleCompletionRequest$(_context5) { | ||
while (1) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
if (!(!params || !params.textDocument || !params.position)) { | ||
_context5.next = 2; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
throw new Error('`textDocument` argument is required.'); | ||
case 32: | ||
textDocument = message.params.textDocument; | ||
pos = message.params.position; | ||
case 2: | ||
textDocument = params.textDocument; | ||
position = params.position; | ||
cachedDocument = getCachedDocument(textDocument.uri); | ||
if (cachedDocument) { | ||
_context2.next = 37; | ||
_context5.next = 7; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
throw new Error(textDocument.uri + ' is not available.'); | ||
case 37: | ||
case 7: | ||
query = cachedDocument.content.text; | ||
_context2.next = 40; | ||
return regeneratorRuntime.awrap(languageService.getDefinition(query, pos, textDocument.uri)); | ||
_context5.next = 10; | ||
return regeneratorRuntime.awrap(languageService.getAutocompleteSuggestions(query, position, textDocument.uri)); | ||
case 40: | ||
result = _context2.sent; | ||
formatted = result ? result.definitions.map(function (res) { | ||
return { | ||
uri: _path2.default.join('file://', res.path), | ||
range: res.range | ||
}; | ||
}) : []; | ||
case 10: | ||
result = _context5.sent; | ||
return _context5.abrupt('return', { items: result, isIncomplete: false }); | ||
sendMessageIPC(convertToRpcMessage({ | ||
id: message.id, | ||
result: formatted | ||
}), writer); | ||
return _context2.abrupt('break', 51); | ||
case 44: | ||
if (!(!message.params || !message.params.id)) { | ||
_context2.next = 46; | ||
break; | ||
} | ||
return _context2.abrupt('return'); | ||
case 46: | ||
requestIDToCancel = message.params.id; | ||
index = REQUEST_IDS_IN_PROGRESS.indexOf(requestIDToCancel); | ||
if (index !== -1) { | ||
REQUEST_IDS_IN_PROGRESS.splice(index, 1); | ||
// A cancelled request still needs to send an empty response back | ||
sendMessageIPC({ id: requestIDToCancel }, writer); | ||
} | ||
return _context2.abrupt('break', 51); | ||
case 50: | ||
return _context2.abrupt('break', 51); | ||
case 51: | ||
case 12: | ||
case 'end': | ||
return _context2.stop(); | ||
return _context5.stop(); | ||
} | ||
@@ -336,155 +257,54 @@ } | ||
function processStreamMessage(message, configDir) { | ||
var graphQLConfigDir, json, id, method, result, responseMsg, _json$args, query, filePath, position, formatted; | ||
return regeneratorRuntime.async(function processStreamMessage$(_context3) { | ||
function handleDefinitionRequest(params, token) { | ||
var textDocument, pos, cachedDocument, query, result, formatted; | ||
return regeneratorRuntime.async(function handleDefinitionRequest$(_context6) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
switch (_context6.prev = _context6.next) { | ||
case 0: | ||
if (!(message.length === 0)) { | ||
_context3.next = 2; | ||
if (!(!params || !params.textDocument || !params.position)) { | ||
_context6.next = 2; | ||
break; | ||
} | ||
return _context3.abrupt('return'); | ||
throw new Error('`textDocument` and `position` arguments are required.'); | ||
case 2: | ||
if (graphQLCache) { | ||
_context3.next = 10; | ||
break; | ||
} | ||
textDocument = params.textDocument; | ||
pos = params.position; | ||
cachedDocument = getCachedDocument(textDocument.uri); | ||
graphQLConfigDir = (0, _graphqlLanguageServiceConfig.findGraphQLConfigDir)(configDir ? configDir.trim() : process.cwd()); | ||
if (graphQLConfigDir) { | ||
_context3.next = 7; | ||
if (cachedDocument) { | ||
_context6.next = 7; | ||
break; | ||
} | ||
process.stdout.write(JSON.stringify(convertToRpcMessage({ | ||
id: '-1', | ||
error: { | ||
code: ERROR_CODES.SERVER_NOT_INITIALIZED, | ||
message: '.graphqlrc not found' | ||
} | ||
}))); | ||
return _context3.abrupt('return'); | ||
throw new Error(textDocument.uri + ' is not available.'); | ||
case 7: | ||
_context3.next = 9; | ||
return regeneratorRuntime.awrap((0, _GraphQLCache.getGraphQLCache)(graphQLConfigDir)); | ||
query = cachedDocument.content.text; | ||
_context6.next = 10; | ||
return regeneratorRuntime.awrap(languageService.getDefinition(query, pos, textDocument.uri)); | ||
case 9: | ||
graphQLCache = _context3.sent; | ||
case 10: | ||
if (!languageService) { | ||
languageService = new _graphqlLanguageServiceInterface.GraphQLLanguageService(graphQLCache); | ||
} | ||
json = void 0; | ||
_context3.prev = 12; | ||
json = JSON.parse(message); | ||
_context3.next = 20; | ||
break; | ||
case 16: | ||
_context3.prev = 16; | ||
_context3.t0 = _context3['catch'](12); | ||
process.stdout.write(JSON.stringify(convertToRpcMessage({ | ||
id: '-1', | ||
error: { | ||
code: ERROR_CODES.PARSE_ERROR, | ||
message: 'Request contains incorrect JSON format' | ||
} | ||
}))); | ||
return _context3.abrupt('return'); | ||
case 20: | ||
id = json.id; | ||
method = json.method; | ||
result = null; | ||
responseMsg = null; | ||
_json$args = json.args, query = _json$args.query, filePath = _json$args.filePath, position = _json$args.position; | ||
_context3.t1 = method; | ||
_context3.next = _context3.t1 === 'disconnect' ? 28 : _context3.t1 === 'getDiagnostics' ? 30 : _context3.t1 === 'getDefinition' ? 36 : _context3.t1 === 'getAutocompleteSuggestions' ? 42 : _context3.t1 === 'getOutline' ? 49 : 53; | ||
break; | ||
case 28: | ||
process.exit(0); | ||
return _context3.abrupt('break', 54); | ||
case 30: | ||
_context3.next = 32; | ||
return regeneratorRuntime.awrap(provideDiagnosticsMessage(query, filePath)); | ||
case 32: | ||
result = _context3.sent; | ||
responseMsg = convertToRpcMessage({ | ||
type: 'response', | ||
id: id, | ||
result: result | ||
}); | ||
process.stdout.write(JSON.stringify(responseMsg) + '\n'); | ||
return _context3.abrupt('break', 54); | ||
case 36: | ||
_context3.next = 38; | ||
return regeneratorRuntime.awrap(languageService.getDefinition(query, position, filePath)); | ||
case 38: | ||
result = _context3.sent; | ||
responseMsg = convertToRpcMessage({ | ||
type: 'response', | ||
id: id, | ||
result: result | ||
}); | ||
process.stdout.write(JSON.stringify(responseMsg) + '\n'); | ||
return _context3.abrupt('break', 54); | ||
case 42: | ||
_context3.next = 44; | ||
return regeneratorRuntime.awrap(languageService.getAutocompleteSuggestions(query, position, filePath)); | ||
case 44: | ||
result = _context3.sent; | ||
formatted = result.map(function (res) { | ||
result = _context6.sent; | ||
formatted = result ? result.definitions.map(function (res) { | ||
return { | ||
text: res.label, | ||
typeName: res.detail ? String(res.detail) : null, | ||
description: res.documentation || null | ||
// TODO: fix this hack! | ||
// URI is being misused all over this library - there's a link that | ||
// defines how an URI should be structured: | ||
// https://tools.ietf.org/html/rfc3986 | ||
// Remove the below hack once the usage of URI is sorted out in related | ||
// libraries. | ||
uri: res.path.indexOf('file:') === 0 ? res.path : _path2.default.join('file:', res.path), | ||
range: res.range | ||
}; | ||
}); | ||
}) : []; | ||
return _context6.abrupt('return', formatted); | ||
responseMsg = convertToRpcMessage({ | ||
type: 'response', | ||
id: id, | ||
formatted: formatted | ||
}); | ||
process.stdout.write(JSON.stringify(responseMsg) + '\n'); | ||
return _context3.abrupt('break', 54); | ||
case 49: | ||
result = (0, _graphqlLanguageServiceInterface.getOutline)(query); | ||
responseMsg = convertToRpcMessage({ | ||
type: 'response', | ||
id: id, | ||
result: result | ||
}); | ||
process.stdout.write(JSON.stringify(responseMsg) + '\n'); | ||
return _context3.abrupt('break', 54); | ||
case 53: | ||
return _context3.abrupt('break', 54); | ||
case 54: | ||
case 13: | ||
case 'end': | ||
return _context3.stop(); | ||
return _context6.stop(); | ||
} | ||
} | ||
}, null, this, [[12, 16]]); | ||
}, null, this); | ||
} | ||
@@ -498,5 +318,5 @@ | ||
var serverCapabilities, configDir; | ||
return regeneratorRuntime.async(function initialize$(_context4) { | ||
return regeneratorRuntime.async(function initialize$(_context7) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context7.prev = _context7.next) { | ||
case 0: | ||
@@ -513,22 +333,22 @@ serverCapabilities = { | ||
if (configDir) { | ||
_context4.next = 4; | ||
_context7.next = 4; | ||
break; | ||
} | ||
return _context4.abrupt('return', null); | ||
return _context7.abrupt('return', null); | ||
case 4: | ||
_context4.next = 6; | ||
_context7.next = 6; | ||
return regeneratorRuntime.awrap((0, _GraphQLCache.getGraphQLCache)(configDir)); | ||
case 6: | ||
graphQLCache = _context4.sent; | ||
graphQLCache = _context7.sent; | ||
languageService = new _graphqlLanguageServiceInterface.GraphQLLanguageService(graphQLCache); | ||
return _context4.abrupt('return', serverCapabilities); | ||
return _context7.abrupt('return', serverCapabilities); | ||
case 9: | ||
case 'end': | ||
return _context4.stop(); | ||
return _context7.stop(); | ||
} | ||
@@ -541,11 +361,11 @@ } | ||
var results, queryLines, totalLines, lastLineLength, lastCharacterPosition; | ||
return regeneratorRuntime.async(function provideDiagnosticsMessage$(_context5) { | ||
return regeneratorRuntime.async(function provideDiagnosticsMessage$(_context8) { | ||
while (1) { | ||
switch (_context5.prev = _context5.next) { | ||
switch (_context8.prev = _context8.next) { | ||
case 0: | ||
_context5.next = 2; | ||
_context8.next = 2; | ||
return regeneratorRuntime.awrap(languageService.getDiagnostics(query, uri)); | ||
case 2: | ||
results = _context5.sent; | ||
results = _context8.sent; | ||
@@ -563,7 +383,7 @@ if (results && results.length > 0) { | ||
return _context5.abrupt('return', results); | ||
return _context8.abrupt('return', results); | ||
case 5: | ||
case 'end': | ||
return _context5.stop(); | ||
return _context8.stop(); | ||
} | ||
@@ -574,18 +394,2 @@ } | ||
function sendMessageIPC(message, writer) { | ||
writer.write(message); | ||
} | ||
/** | ||
* Composes a language server protocol JSON message. | ||
*/ | ||
function convertToRpcMessage(metaMessage) { | ||
var message = _extends({ | ||
jsonrpc: '2.0', | ||
protocol: 'graphql_language_service' | ||
}, metaMessage); | ||
return message; | ||
} | ||
function invalidateCache(textDocument, uri, content) { | ||
@@ -592,0 +396,0 @@ if (!uri) { |
@@ -15,6 +15,19 @@ 'use strict'; | ||
var _vscodeLanguageserver = require('vscode-languageserver'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
* Copyright (c) Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
*/ | ||
exports.default = function startServer(options) { | ||
var configDir; | ||
var configDir, reader, writer, _port, socket, connection; | ||
return regeneratorRuntime.async(function startServer$(_context) { | ||
@@ -24,31 +37,75 @@ while (1) { | ||
case 0: | ||
if (!options || !options.configDir) { | ||
process.stderr.write('--configDir is required!'); | ||
process.exit(1); | ||
if (options) { | ||
_context.next = 4; | ||
break; | ||
} | ||
process.stderr.write('At least --configDir option is required.'); | ||
process.exit(1); | ||
return _context.abrupt('return'); | ||
case 4: | ||
if (options.configDir) { | ||
_context.next = 8; | ||
break; | ||
} | ||
process.stderr.write('--configDir is required.'); | ||
process.exit(1); | ||
return _context.abrupt('return'); | ||
case 8: | ||
configDir = options.configDir; | ||
if (!(options && options.method)) { | ||
_context.next = 12; | ||
_context.next = 31; | ||
break; | ||
} | ||
reader = void 0; | ||
writer = void 0; | ||
_context.t0 = options.method; | ||
_context.next = _context.t0 === 'stream' ? 6 : _context.t0 === 'socket' ? 8 : _context.t0 === 'node' ? 10 : 10; | ||
_context.next = _context.t0 === 'stream' ? 15 : _context.t0 === 'socket' ? 18 : _context.t0 === 'node' ? 25 : 25; | ||
break; | ||
case 6: | ||
connectWithStream(configDir); | ||
return _context.abrupt('break', 12); | ||
case 15: | ||
reader = new _vscodeJsonrpc.StreamMessageReader(process.stdin); | ||
writer = new _vscodeJsonrpc.StreamMessageWriter(process.stdout); | ||
return _context.abrupt('break', 28); | ||
case 8: | ||
connectWithSocket(configDir, options.port); | ||
return _context.abrupt('break', 12); | ||
case 18: | ||
if (options.port) { | ||
_context.next = 22; | ||
break; | ||
} | ||
case 10: | ||
connectWithNodeIPC(configDir); | ||
return _context.abrupt('break', 12); | ||
process.stderr.write('--port is required to establish socket connection.'); | ||
process.exit(1); | ||
return _context.abrupt('return'); | ||
case 12: | ||
case 22: | ||
_port = options.port; | ||
socket = _net2.default.createServer(function (client) { | ||
client.setEncoding('utf8'); | ||
reader = new _vscodeJsonrpc.SocketMessageReader(client); | ||
writer = new _vscodeJsonrpc.SocketMessageWriter(client); | ||
client.on('end', function () { | ||
socket.close(); | ||
process.exit(0); | ||
}); | ||
}).listen(_port); | ||
return _context.abrupt('break', 28); | ||
case 25: | ||
reader = new _vscodeJsonrpc.IPCMessageReader(process); | ||
writer = new _vscodeJsonrpc.IPCMessageWriter(process); | ||
return _context.abrupt('break', 28); | ||
case 28: | ||
connection = (0, _vscodeJsonrpc.createMessageConnection)(reader, writer); | ||
addHandlers(connection, configDir); | ||
connection.listen(); | ||
case 31: | ||
case 'end': | ||
@@ -59,86 +116,93 @@ return _context.stop(); | ||
}, null, this); | ||
}; /** | ||
* Copyright (c) Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* | ||
*/ | ||
}; | ||
function connectWithSocket(configDir, port) { | ||
var socket = _net2.default.createServer(function (client) { | ||
client.setEncoding('utf8'); | ||
var messageReader = new _vscodeJsonrpc.SocketMessageReader(client); | ||
var messageWriter = new _vscodeJsonrpc.SocketMessageWriter(client); | ||
function addHandlers(connection, configDir) { | ||
var _this = this; | ||
client.on('end', function () { | ||
socket.close(); | ||
process.exit(0); | ||
}); | ||
connection.onNotification(_vscodeLanguageserver.DidOpenTextDocumentNotification.type, function _callee(params) { | ||
var diagnostics; | ||
return regeneratorRuntime.async(function _callee$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
_context2.next = 2; | ||
return regeneratorRuntime.awrap((0, _MessageProcessor.handleDidOpenOrSaveNotification)(params)); | ||
messageReader.listen(function (message) { | ||
try { | ||
if (message.id != null) { | ||
(0, _MessageProcessor.processIPCRequestMessage)(message, configDir, messageWriter); | ||
} else { | ||
(0, _MessageProcessor.processIPCNotificationMessage)(message, messageWriter); | ||
case 2: | ||
diagnostics = _context2.sent; | ||
if (diagnostics) { | ||
connection.sendNotification(_vscodeLanguageserver.PublishDiagnosticsNotification.type, diagnostics); | ||
} | ||
case 4: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} catch (error) { | ||
// Swallow error silently. | ||
} | ||
}); | ||
}, null, _this); | ||
}); | ||
connection.onNotification(_vscodeLanguageserver.DidSaveTextDocumentNotification.type, function _callee2(params) { | ||
var diagnostics; | ||
return regeneratorRuntime.async(function _callee2$(_context3) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
_context3.next = 2; | ||
return regeneratorRuntime.awrap((0, _MessageProcessor.handleDidOpenOrSaveNotification)(params)); | ||
socket.listen(port); | ||
} | ||
case 2: | ||
diagnostics = _context3.sent; | ||
function connectWithNodeIPC(configDir) { | ||
// IPC protocol support | ||
// The language server protocol specifies that the client starts sending | ||
// messages when the server starts. Start listening from this point. | ||
var ipcWriter = new _vscodeJsonrpc.IPCMessageWriter(process); | ||
var ipcReader = new _vscodeJsonrpc.IPCMessageReader(process); | ||
ipcReader.listen(function (message) { | ||
try { | ||
if (message.id != null) { | ||
(0, _MessageProcessor.processIPCRequestMessage)(message, configDir, ipcWriter); | ||
} else { | ||
(0, _MessageProcessor.processIPCNotificationMessage)(message, ipcWriter); | ||
if (diagnostics) { | ||
connection.sendNotification(_vscodeLanguageserver.PublishDiagnosticsNotification.type, diagnostics); | ||
} | ||
case 4: | ||
case 'end': | ||
return _context3.stop(); | ||
} | ||
} | ||
} catch (error) { | ||
// Swallow error silently. | ||
} | ||
}, null, _this); | ||
}); | ||
} | ||
connection.onNotification(_vscodeLanguageserver.DidChangeTextDocumentNotification.type, function _callee3(params) { | ||
var diagnostics; | ||
return regeneratorRuntime.async(function _callee3$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
_context4.next = 2; | ||
return regeneratorRuntime.awrap((0, _MessageProcessor.handleDidChangeNotification)(params)); | ||
function connectWithStream(configDir) { | ||
// Stream (stdio) protocol support | ||
// Depending on the size of the query, incomplete query strings | ||
// may be streamed in. The below code tries to detect the end of current | ||
// batch of streamed data, splits the batch into appropriate JSON string, | ||
// and calls the function to process those messages. | ||
// This might get tricky since the query string needs to preserve the newline | ||
// characters to ensure the correct Range/Point values gets computed by the | ||
// language service interface methods. The current solution is to flow the | ||
// stream until aggregated data ends with the unescaped newline character, | ||
// pauses the stream and process the messages, and resumes back the stream | ||
// for another batch. | ||
var data = ''; | ||
process.stdin.setEncoding('utf8'); | ||
process.stdin.on('data', function (chunk) { | ||
data += chunk.toString(); | ||
case 2: | ||
diagnostics = _context4.sent; | ||
// Check if the current buffer contains newline character. | ||
var flagPosition = data.indexOf('\r\n'); | ||
if (flagPosition !== -1) { | ||
// There may be more than one message in the buffer. | ||
var messages = data.split('\r\n'); | ||
data = messages.pop().trim(); | ||
messages.forEach(function (message) { | ||
return (0, _MessageProcessor.processStreamMessage)(message, configDir); | ||
}); | ||
} | ||
if (diagnostics) { | ||
connection.sendNotification(_vscodeLanguageserver.PublishDiagnosticsNotification.type, diagnostics); | ||
} | ||
case 4: | ||
case 'end': | ||
return _context4.stop(); | ||
} | ||
} | ||
}, null, _this); | ||
}); | ||
connection.onNotification(_vscodeLanguageserver.DidCloseTextDocumentNotification.type, _MessageProcessor.handleDidCloseNotification); | ||
connection.onNotification(_vscodeLanguageserver.ExitNotification.type, function () { | ||
return process.exit(0); | ||
}); | ||
// Ignore cancel requests | ||
connection.onNotification('$/cancelRequest', function () { | ||
return {}; | ||
}); | ||
connection.onRequest(_vscodeLanguageserver.InitializeRequest.type, function (params, token) { | ||
return (0, _MessageProcessor.handleInitializeRequest)(params, token, configDir); | ||
}); | ||
connection.onRequest(_vscodeLanguageserver.CompletionRequest.type, _MessageProcessor.handleCompletionRequest); | ||
connection.onRequest(_vscodeLanguageserver.CompletionResolveRequest.type, function (item) { | ||
return item; | ||
}); | ||
connection.onRequest(_vscodeLanguageserver.DefinitionRequest.type, _MessageProcessor.handleDefinitionRequest); | ||
} |
{ | ||
"name": "graphql-language-service-server", | ||
"repository": "https://github.com/graphql/graphql-language-service", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "Server process backing the GraphQL Language Service", | ||
@@ -36,4 +36,5 @@ "contributors": [ | ||
"nullthrows": "^1.0.0", | ||
"vscode-jsonrpc": "^3.2.0" | ||
"vscode-jsonrpc": "^3.2.0", | ||
"vscode-languageserver": "^3.2.0" | ||
} | ||
} |
@@ -14,3 +14,3 @@ # GraphQL Language Service | ||
- Autocomplete suggestions (**spec-compliant**) | ||
- Hyperlink to fragment definitions | ||
- Hyperlink to fragment definitions (**spec-compliant**) | ||
- Outline view support for queries | ||
@@ -17,0 +17,0 @@ |
{ | ||
"graphql-language-service": { | ||
"version": "0.0.9" | ||
"version": "0.0.10" | ||
}, | ||
@@ -18,3 +18,3 @@ "graphql-language-server": { | ||
"graphql-language-service-server": { | ||
"version": "0.0.10" | ||
"version": "0.0.11" | ||
}, | ||
@@ -21,0 +21,0 @@ "graphql-language-service-types": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
300481
-3.53%14
7.69%3984
-2.57%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed