/* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ /// 'use strict'; function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; } Object.defineProperty(exports, "__esModule", { value: true }); const Is = require("./is"); const messages_1 = require("./messages"); exports.RequestType = messages_1.RequestType; exports.RequestType0 = messages_1.RequestType0; exports.RequestType1 = messages_1.RequestType1; exports.RequestType2 = messages_1.RequestType2; exports.RequestType3 = messages_1.RequestType3; exports.RequestType4 = messages_1.RequestType4; exports.RequestType5 = messages_1.RequestType5; exports.RequestType6 = messages_1.RequestType6; exports.RequestType7 = messages_1.RequestType7; exports.RequestType8 = messages_1.RequestType8; exports.RequestType9 = messages_1.RequestType9; exports.ResponseError = messages_1.ResponseError; exports.ErrorCodes = messages_1.ErrorCodes; exports.NotificationType = messages_1.NotificationType; exports.NotificationType0 = messages_1.NotificationType0; exports.NotificationType1 = messages_1.NotificationType1; exports.NotificationType2 = messages_1.NotificationType2; exports.NotificationType3 = messages_1.NotificationType3; exports.NotificationType4 = messages_1.NotificationType4; exports.NotificationType5 = messages_1.NotificationType5; exports.NotificationType6 = messages_1.NotificationType6; exports.NotificationType7 = messages_1.NotificationType7; exports.NotificationType8 = messages_1.NotificationType8; exports.NotificationType9 = messages_1.NotificationType9; const messageReader_1 = require("./messageReader"); exports.MessageReader = messageReader_1.MessageReader; exports.StreamMessageReader = messageReader_1.StreamMessageReader; exports.IPCMessageReader = messageReader_1.IPCMessageReader; exports.SocketMessageReader = messageReader_1.SocketMessageReader; const messageWriter_1 = require("./messageWriter"); exports.MessageWriter = messageWriter_1.MessageWriter; exports.StreamMessageWriter = messageWriter_1.StreamMessageWriter; exports.IPCMessageWriter = messageWriter_1.IPCMessageWriter; exports.SocketMessageWriter = messageWriter_1.SocketMessageWriter; const events_1 = require("./events"); exports.Disposable = events_1.Disposable; exports.Event = events_1.Event; exports.Emitter = events_1.Emitter; const cancellation_1 = require("./cancellation"); exports.CancellationTokenSource = cancellation_1.CancellationTokenSource; exports.CancellationToken = cancellation_1.CancellationToken; const linkedMap_1 = require("./linkedMap"); __export(require("./pipeSupport")); __export(require("./socketSupport")); var CancelNotification; (function (CancelNotification) { CancelNotification.type = new messages_1.NotificationType('$/cancelRequest'); })(CancelNotification || (CancelNotification = {})); exports.NullLogger = Object.freeze({ error: () => { }, warn: () => { }, info: () => { }, log: () => { } }); var Trace; (function (Trace) { Trace[Trace["Off"] = 0] = "Off"; Trace[Trace["Messages"] = 1] = "Messages"; Trace[Trace["Verbose"] = 2] = "Verbose"; })(Trace = exports.Trace || (exports.Trace = {})); (function (Trace) { function fromString(value) { value = value.toLowerCase(); switch (value) { case 'off': return Trace.Off; case 'messages': return Trace.Messages; case 'verbose': return Trace.Verbose; default: return Trace.Off; } } Trace.fromString = fromString; function toString(value) { switch (value) { case Trace.Off: return 'off'; case Trace.Messages: return 'messages'; case Trace.Verbose: return 'verbose'; default: return 'off'; } } Trace.toString = toString; })(Trace = exports.Trace || (exports.Trace = {})); var TraceFormat; (function (TraceFormat) { TraceFormat["Text"] = "text"; TraceFormat["JSON"] = "json"; })(TraceFormat = exports.TraceFormat || (exports.TraceFormat = {})); (function (TraceFormat) { function fromString(value) { value = value.toLowerCase(); if (value === 'json') { return TraceFormat.JSON; } else { return TraceFormat.Text; } } TraceFormat.fromString = fromString; })(TraceFormat = exports.TraceFormat || (exports.TraceFormat = {})); var SetTraceNotification; (function (SetTraceNotification) { SetTraceNotification.type = new messages_1.NotificationType('$/setTraceNotification'); })(SetTraceNotification = exports.SetTraceNotification || (exports.SetTraceNotification = {})); var LogTraceNotification; (function (LogTraceNotification) { LogTraceNotification.type = new messages_1.NotificationType('$/logTraceNotification'); })(LogTraceNotification = exports.LogTraceNotification || (exports.LogTraceNotification = {})); var ConnectionErrors; (function (ConnectionErrors) { /** * The connection is closed. */ ConnectionErrors[ConnectionErrors["Closed"] = 1] = "Closed"; /** * The connection got disposed. */ ConnectionErrors[ConnectionErrors["Disposed"] = 2] = "Disposed"; /** * The connection is already in listening mode. */ ConnectionErrors[ConnectionErrors["AlreadyListening"] = 3] = "AlreadyListening"; })(ConnectionErrors = exports.ConnectionErrors || (exports.ConnectionErrors = {})); class ConnectionError extends Error { constructor(code, message) { super(message); this.code = code; Object.setPrototypeOf(this, ConnectionError.prototype); } } exports.ConnectionError = ConnectionError; var ConnectionStrategy; (function (ConnectionStrategy) { function is(value) { let candidate = value; return candidate && Is.func(candidate.cancelUndispatched); } ConnectionStrategy.is = is; })(ConnectionStrategy = exports.ConnectionStrategy || (exports.ConnectionStrategy = {})); var ConnectionState; (function (ConnectionState) { ConnectionState[ConnectionState["New"] = 1] = "New"; ConnectionState[ConnectionState["Listening"] = 2] = "Listening"; ConnectionState[ConnectionState["Closed"] = 3] = "Closed"; ConnectionState[ConnectionState["Disposed"] = 4] = "Disposed"; })(ConnectionState || (ConnectionState = {})); function _createMessageConnection(messageReader, messageWriter, logger, strategy) { let sequenceNumber = 0; let notificationSquenceNumber = 0; let unknownResponseSquenceNumber = 0; const version = '2.0'; let starRequestHandler = undefined; let requestHandlers = Object.create(null); let starNotificationHandler = undefined; let notificationHandlers = Object.create(null); let timer; let messageQueue = new linkedMap_1.LinkedMap(); let responsePromises = Object.create(null); let requestTokens = Object.create(null); let trace = Trace.Off; let traceFormat = TraceFormat.Text; let tracer; let state = ConnectionState.New; let errorEmitter = new events_1.Emitter(); let closeEmitter = new events_1.Emitter(); let unhandledNotificationEmitter = new events_1.Emitter(); let disposeEmitter = new events_1.Emitter(); function createRequestQueueKey(id) { return 'req-' + id.toString(); } function createResponseQueueKey(id) { if (id === null) { return 'res-unknown-' + (++unknownResponseSquenceNumber).toString(); } else { return 'res-' + id.toString(); } } function createNotificationQueueKey() { return 'not-' + (++notificationSquenceNumber).toString(); } function addMessageToQueue(queue, message) { if (messages_1.isRequestMessage(message)) { queue.set(createRequestQueueKey(message.id), message); } else if (messages_1.isResponseMessage(message)) { queue.set(createResponseQueueKey(message.id), message); } else { queue.set(createNotificationQueueKey(), message); } } function cancelUndispatched(_message) { return undefined; } function isListening() { return state === ConnectionState.Listening; } function isClosed() { return state === ConnectionState.Closed; } function isDisposed() { return state === ConnectionState.Disposed; } function closeHandler() { if (state === ConnectionState.New || state === ConnectionState.Listening) { state = ConnectionState.Closed; closeEmitter.fire(undefined); } // If the connection is disposed don't sent close events. } ; function readErrorHandler(error) { errorEmitter.fire([error, undefined, undefined]); } function writeErrorHandler(data) { errorEmitter.fire(data); } messageReader.onClose(closeHandler); messageReader.onError(readErrorHandler); messageWriter.onClose(closeHandler); messageWriter.onError(writeErrorHandler); function triggerMessageQueue() { if (timer || messageQueue.size === 0) { return; } timer = setImmediate(() => { timer = undefined; processMessageQueue(); }); } function processMessageQueue() { if (messageQueue.size === 0) { return; } let message = messageQueue.shift(); try { if (messages_1.isRequestMessage(message)) { handleRequest(message); } else if (messages_1.isNotificationMessage(message)) { handleNotification(message); } else if (messages_1.isResponseMessage(message)) { handleResponse(message); } else { handleInvalidMessage(message); } } finally { triggerMessageQueue(); } } let callback = (message) => { try { // We have received a cancellation message. Check if the message is still in the queue // and cancel it if allowed to do so. if (messages_1.isNotificationMessage(message) && message.method === CancelNotification.type.method) { let key = createRequestQueueKey(message.params.id); let toCancel = messageQueue.get(key); if (messages_1.isRequestMessage(toCancel)) { let response = strategy && strategy.cancelUndispatched ? strategy.cancelUndispatched(toCancel, cancelUndispatched) : cancelUndispatched(toCancel); if (response && (response.error !== void 0 || response.result !== void 0)) { messageQueue.delete(key); response.id = toCancel.id; traceSendingResponse(response, message.method, Date.now()); messageWriter.write(response); return; } } } addMessageToQueue(messageQueue, message); } finally { triggerMessageQueue(); } }; function handleRequest(requestMessage) { if (isDisposed()) { // we return here silently since we fired an event when the // connection got disposed. return; } function reply(resultOrError, method, startTime) { let message = { jsonrpc: version, id: requestMessage.id }; if (resultOrError instanceof messages_1.ResponseError) { message.error = resultOrError.toJson(); } else { message.result = resultOrError === void 0 ? null : resultOrError; } traceSendingResponse(message, method, startTime); messageWriter.write(message); } function replyError(error, method, startTime) { let message = { jsonrpc: version, id: requestMessage.id, error: error.toJson() }; traceSendingResponse(message, method, startTime); messageWriter.write(message); } function replySuccess(result, method, startTime) { // The JSON RPC defines that a response must either have a result or an error // So we can't treat undefined as a valid response result. if (result === void 0) { result = null; } let message = { jsonrpc: version, id: requestMessage.id, result: result }; traceSendingResponse(message, method, startTime); messageWriter.write(message); } traceReceivedRequest(requestMessage); let element = requestHandlers[requestMessage.method]; let type; let requestHandler; if (element) { type = element.type; requestHandler = element.handler; } let startTime = Date.now(); if (requestHandler || starRequestHandler) { let cancellationSource = new cancellation_1.CancellationTokenSource(); let tokenKey = String(requestMessage.id); requestTokens[tokenKey] = cancellationSource; try { let handlerResult; if (requestMessage.params === void 0 || (type !== void 0 && type.numberOfParams === 0)) { handlerResult = requestHandler ? requestHandler(cancellationSource.token) : starRequestHandler(requestMessage.method, cancellationSource.token); } else if (Is.array(requestMessage.params) && (type === void 0 || type.numberOfParams > 1)) { handlerResult = requestHandler ? requestHandler(...requestMessage.params, cancellationSource.token) : starRequestHandler(requestMessage.method, ...requestMessage.params, cancellationSource.token); } else { handlerResult = requestHandler ? requestHandler(requestMessage.params, cancellationSource.token) : starRequestHandler(requestMessage.method, requestMessage.params, cancellationSource.token); } let promise = handlerResult; if (!handlerResult) { delete requestTokens[tokenKey]; replySuccess(handlerResult, requestMessage.method, startTime); } else if (promise.then) { promise.then((resultOrError) => { delete requestTokens[tokenKey]; reply(resultOrError, requestMessage.method, startTime); }, error => { delete requestTokens[tokenKey]; if (error instanceof messages_1.ResponseError) { replyError(error, requestMessage.method, startTime); } else if (error && Is.string(error.message)) { replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime); } else { replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime); } }); } else { delete requestTokens[tokenKey]; reply(handlerResult, requestMessage.method, startTime); } } catch (error) { delete requestTokens[tokenKey]; if (error instanceof messages_1.ResponseError) { reply(error, requestMessage.method, startTime); } else if (error && Is.string(error.message)) { replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed with message: ${error.message}`), requestMessage.method, startTime); } else { replyError(new messages_1.ResponseError(messages_1.ErrorCodes.InternalError, `Request ${requestMessage.method} failed unexpectedly without providing any details.`), requestMessage.method, startTime); } } } else { replyError(new messages_1.ResponseError(messages_1.ErrorCodes.MethodNotFound, `Unhandled method ${requestMessage.method}`), requestMessage.method, startTime); } } function handleResponse(responseMessage) { if (isDisposed()) { // See handle request. return; } if (responseMessage.id === null) { if (responseMessage.error) { logger.error(`Received response message without id: Error is: \n${JSON.stringify(responseMessage.error, undefined, 4)}`); } else { logger.error(`Received response message without id. No further error information provided.`); } } else { let key = String(responseMessage.id); let responsePromise = responsePromises[key]; traceReceivedResponse(responseMessage, responsePromise); if (responsePromise) { delete responsePromises[key]; try { if (responseMessage.error) { let error = responseMessage.error; responsePromise.reject(new messages_1.ResponseError(error.code, error.message, error.data)); } else if (responseMessage.result !== void 0) { responsePromise.resolve(responseMessage.result); } else { throw new Error('Should never happen.'); } } catch (error) { if (error.message) { logger.error(`Response handler '${responsePromise.method}' failed with message: ${error.message}`); } else { logger.error(`Response handler '${responsePromise.method}' failed unexpectedly.`); } } } } } function handleNotification(message) { if (isDisposed()) { // See handle request. return; } let type = undefined; let notificationHandler; if (message.method === CancelNotification.type.method) { notificationHandler = (params) => { let id = params.id; let source = requestTokens[String(id)]; if (source) { source.cancel(); } }; } else { let element = notificationHandlers[message.method]; if (element) { notificationHandler = element.handler; type = element.type; } } if (notificationHandler || starNotificationHandler) { try { traceReceivedNotification(message); if (message.params === void 0 || (type !== void 0 && type.numberOfParams === 0)) { notificationHandler ? notificationHandler() : starNotificationHandler(message.method); } else if (Is.array(message.params) && (type === void 0 || type.numberOfParams > 1)) { notificationHandler ? notificationHandler(...message.params) : starNotificationHandler(message.method, ...message.params); } else { notificationHandler ? notificationHandler(message.params) : starNotificationHandler(message.method, message.params); } } catch (error) { if (error.message) { logger.error(`Notification handler '${message.method}' failed with message: ${error.message}`); } else { logger.error(`Notification handler '${message.method}' failed unexpectedly.`); } } } else { unhandledNotificationEmitter.fire(message); } } function handleInvalidMessage(message) { if (!message) { logger.error('Received empty message.'); return; } logger.error(`Received message which is neither a response nor a notification message:\n${JSON.stringify(message, null, 4)}`); // Test whether we find an id to reject the promise let responseMessage = message; if (Is.string(responseMessage.id) || Is.number(responseMessage.id)) { let key = String(responseMessage.id); let responseHandler = responsePromises[key]; if (responseHandler) { responseHandler.reject(new Error('The received response has neither a result nor an error property.')); } } } function traceSendingRequest(message) { if (trace === Trace.Off || !tracer) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose && message.params) { data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; } tracer.log(`Sending request '${message.method} - (${message.id})'.`, data); } else { logLSPMessage('send-request', message); } } function traceSendingNotification(message) { if (trace === Trace.Off || !tracer) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose) { if (message.params) { data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; } else { data = 'No parameters provided.\n\n'; } } tracer.log(`Sending notification '${message.method}'.`, data); } else { logLSPMessage('send-notification', message); } } function traceSendingResponse(message, method, startTime) { if (trace === Trace.Off || !tracer) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose) { if (message.error && message.error.data) { data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; } else { if (message.result) { data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; } else if (message.error === void 0) { data = 'No result returned.\n\n'; } } } tracer.log(`Sending response '${method} - (${message.id})'. Processing request took ${Date.now() - startTime}ms`, data); } else { logLSPMessage('send-response', message); } } function traceReceivedRequest(message) { if (trace === Trace.Off || !tracer) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose && message.params) { data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; } tracer.log(`Received request '${message.method} - (${message.id})'.`, data); } else { logLSPMessage('receive-request', message); } } function traceReceivedNotification(message) { if (trace === Trace.Off || !tracer || message.method === LogTraceNotification.type.method) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose) { if (message.params) { data = `Params: ${JSON.stringify(message.params, null, 4)}\n\n`; } else { data = 'No parameters provided.\n\n'; } } tracer.log(`Received notification '${message.method}'.`, data); } else { logLSPMessage('receive-notification', message); } } function traceReceivedResponse(message, responsePromise) { if (trace === Trace.Off || !tracer) { return; } if (traceFormat === TraceFormat.Text) { let data = undefined; if (trace === Trace.Verbose) { if (message.error && message.error.data) { data = `Error data: ${JSON.stringify(message.error.data, null, 4)}\n\n`; } else { if (message.result) { data = `Result: ${JSON.stringify(message.result, null, 4)}\n\n`; } else if (message.error === void 0) { data = 'No result returned.\n\n'; } } } if (responsePromise) { let error = message.error ? ` Request failed: ${message.error.message} (${message.error.code}).` : ''; tracer.log(`Received response '${responsePromise.method} - (${message.id})' in ${Date.now() - responsePromise.timerStart}ms.${error}`, data); } else { tracer.log(`Received response ${message.id} without active response promise.`, data); } } else { logLSPMessage('receive-response', message); } } function logLSPMessage(type, message) { if (!tracer || trace === Trace.Off) { return; } const lspMessage = { isLSPMessage: true, type, message, timestamp: Date.now() }; tracer.log(lspMessage); } function throwIfClosedOrDisposed() { if (isClosed()) { throw new ConnectionError(ConnectionErrors.Closed, 'Connection is closed.'); } if (isDisposed()) { throw new ConnectionError(ConnectionErrors.Disposed, 'Connection is disposed.'); } } function throwIfListening() { if (isListening()) { throw new ConnectionError(ConnectionErrors.AlreadyListening, 'Connection is already listening'); } } function throwIfNotListening() { if (!isListening()) { throw new Error('Call listen() first.'); } } function undefinedToNull(param) { if (param === void 0) { return null; } else { return param; } } function computeMessageParams(type, params) { let result; let numberOfParams = type.numberOfParams; switch (numberOfParams) { case 0: result = null; break; case 1: result = undefinedToNull(params[0]); break; default: result = []; for (let i = 0; i < params.length && i < numberOfParams; i++) { result.push(undefinedToNull(params[i])); } if (params.length < numberOfParams) { for (let i = params.length; i < numberOfParams; i++) { result.push(null); } } break; } return result; } let connection = { sendNotification: (type, ...params) => { throwIfClosedOrDisposed(); let method; let messageParams; if (Is.string(type)) { method = type; switch (params.length) { case 0: messageParams = null; break; case 1: messageParams = params[0]; break; default: messageParams = params; break; } } else { method = type.method; messageParams = computeMessageParams(type, params); } let notificationMessage = { jsonrpc: version, method: method, params: messageParams }; traceSendingNotification(notificationMessage); messageWriter.write(notificationMessage); }, onNotification: (type, handler) => { throwIfClosedOrDisposed(); if (Is.func(type)) { starNotificationHandler = type; } else if (handler) { if (Is.string(type)) { notificationHandlers[type] = { type: undefined, handler }; } else { notificationHandlers[type.method] = { type, handler }; } } }, sendRequest: (type, ...params) => { throwIfClosedOrDisposed(); throwIfNotListening(); let method; let messageParams; let token = undefined; if (Is.string(type)) { method = type; switch (params.length) { case 0: messageParams = null; break; case 1: // The cancellation token is optional so it can also be undefined. if (cancellation_1.CancellationToken.is(params[0])) { messageParams = null; token = params[0]; } else { messageParams = undefinedToNull(params[0]); } break; default: const last = params.length - 1; if (cancellation_1.CancellationToken.is(params[last])) { token = params[last]; if (params.length === 2) { messageParams = undefinedToNull(params[0]); } else { messageParams = params.slice(0, last).map(value => undefinedToNull(value)); } } else { messageParams = params.map(value => undefinedToNull(value)); } break; } } else { method = type.method; messageParams = computeMessageParams(type, params); let numberOfParams = type.numberOfParams; token = cancellation_1.CancellationToken.is(params[numberOfParams]) ? params[numberOfParams] : undefined; } let id = sequenceNumber++; let result = new Promise((resolve, reject) => { let requestMessage = { jsonrpc: version, id: id, method: method, params: messageParams }; let responsePromise = { method: method, timerStart: Date.now(), resolve, reject }; traceSendingRequest(requestMessage); try { messageWriter.write(requestMessage); } catch (e) { // Writing the message failed. So we need to reject the promise. responsePromise.reject(new messages_1.ResponseError(messages_1.ErrorCodes.MessageWriteError, e.message ? e.message : 'Unknown reason')); responsePromise = null; } if (responsePromise) { responsePromises[String(id)] = responsePromise; } }); if (token) { token.onCancellationRequested(() => { connection.sendNotification(CancelNotification.type, { id }); }); } return result; }, onRequest: (type, handler) => { throwIfClosedOrDisposed(); if (Is.func(type)) { starRequestHandler = type; } else if (handler) { if (Is.string(type)) { requestHandlers[type] = { type: undefined, handler }; } else { requestHandlers[type.method] = { type, handler }; } } }, trace: (_value, _tracer, sendNotificationOrTraceOptions) => { let _sendNotification = false; let _traceFormat = TraceFormat.Text; if (sendNotificationOrTraceOptions !== void 0) { if (Is.boolean(sendNotificationOrTraceOptions)) { _sendNotification = sendNotificationOrTraceOptions; } else { _sendNotification = sendNotificationOrTraceOptions.sendNotification || false; _traceFormat = sendNotificationOrTraceOptions.traceFormat || TraceFormat.Text; } } trace = _value; traceFormat = _traceFormat; if (trace === Trace.Off) { tracer = undefined; } else { tracer = _tracer; } if (_sendNotification && !isClosed() && !isDisposed()) { connection.sendNotification(SetTraceNotification.type, { value: Trace.toString(_value) }); } }, onError: errorEmitter.event, onClose: closeEmitter.event, onUnhandledNotification: unhandledNotificationEmitter.event, onDispose: disposeEmitter.event, dispose: () => { if (isDisposed()) { return; } state = ConnectionState.Disposed; disposeEmitter.fire(undefined); let error = new Error('Connection got disposed.'); Object.keys(responsePromises).forEach((key) => { responsePromises[key].reject(error); }); responsePromises = Object.create(null); requestTokens = Object.create(null); messageQueue = new linkedMap_1.LinkedMap(); // Test for backwards compatibility if (Is.func(messageWriter.dispose)) { messageWriter.dispose(); } if (Is.func(messageReader.dispose)) { messageReader.dispose(); } }, listen: () => { throwIfClosedOrDisposed(); throwIfListening(); state = ConnectionState.Listening; messageReader.listen(callback); }, inspect: () => { console.log("inspect"); } }; connection.onNotification(LogTraceNotification.type, (params) => { if (trace === Trace.Off || !tracer) { return; } tracer.log(params.message, trace === Trace.Verbose ? params.verbose : undefined); }); return connection; } function isMessageReader(value) { return value.listen !== void 0 && value.read === void 0; } function isMessageWriter(value) { return value.write !== void 0 && value.end === void 0; } function createMessageConnection(input, output, logger, strategy) { if (!logger) { logger = exports.NullLogger; } let reader = isMessageReader(input) ? input : new messageReader_1.StreamMessageReader(input); let writer = isMessageWriter(output) ? output : new messageWriter_1.StreamMessageWriter(output); return _createMessageConnection(reader, writer, logger, strategy); } exports.createMessageConnection = createMessageConnection;