/* --------------------------------------------------------------------------------------------
 * Copyright (c) Remy Suen. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for license information.
 * ------------------------------------------------------------------------------------------ */
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
const node_1 = require("vscode-languageserver/node");
const files_1 = require("vscode-languageserver/lib/node/files");
const dockerfile_utils_1 = require("dockerfile-utils");
const dockerfile_language_service_1 = require("dockerfile-language-service");
let formatterConfiguration = null;
/**
 * The settings to use for the validator if the client doesn't support
 * workspace/configuration requests.
 */
let validatorSettings = null;
const formatterConfigurations = new Map();
/**
 * The validator settings that correspond to an individual file retrieved via
 * the workspace/configuration request.
 */
let validatorConfigurations = new Map();
let connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
let service = dockerfile_language_service_1.DockerfileLanguageServiceFactory.createLanguageService();
service.setLogger({
    log(message) {
        connection.console.log(message);
    }
});
/**
 * Whether the client supports the workspace/applyEdit request.
 */
let applyEditSupport = false;
/**
 * Whether the client supports the workspace/configuration request.
 */
let configurationSupport = false;
let documentChangesSupport = false;
let codeActionQuickFixSupport = false;
let documents = {};
/**
 * Retrieves a text document for the file located at the given URI
 * string.
 *
 * @param uri the URI of the interested file, must be defined and not
 *            null
 * @return the text document for the file, or null if no file exists
 *         at the given location
 */
function getDocument(uri) {
    if (documents[uri]) {
        return Promise.resolve(documents[uri]);
    }
    return new Promise((resolve, reject) => {
        let file = (0, files_1.uriToFilePath)(uri);
        if (file === undefined) {
            resolve(null);
        }
        else {
            fs.exists(file, (exists) => {
                if (exists) {
                    fs.readFile(file, (err, data) => {
                        resolve(vscode_languageserver_textdocument_1.TextDocument.create(uri, "dockerfile", 1, data.toString()));
                    });
                }
                else {
                    resolve(null);
                }
            });
        }
    });
}
function supportsDeprecatedItems(capabilities) {
    return capabilities.textDocument
        && capabilities.textDocument.completion
        && capabilities.textDocument.completion.completionItem
        && capabilities.textDocument.completion.completionItem.deprecatedSupport;
}
function supportsSnippets(capabilities) {
    return capabilities.textDocument
        && capabilities.textDocument.completion
        && capabilities.textDocument.completion.completionItem
        && capabilities.textDocument.completion.completionItem.snippetSupport;
}
function supportsCodeActionQuickFixes(capabilities) {
    let values = capabilities.textDocument
        && capabilities.textDocument.codeAction
        && capabilities.textDocument.codeAction.codeActionLiteralSupport
        && capabilities.textDocument.codeAction.codeActionLiteralSupport.codeActionKind
        && capabilities.textDocument.codeAction.codeActionLiteralSupport.codeActionKind.valueSet;
    if (values === null || values === undefined) {
        return false;
    }
    for (let value of values) {
        if (value === node_1.CodeActionKind.QuickFix) {
            return true;
        }
    }
    return false;
}
/**
 * Gets the MarkupKind[] that the client supports for the
 * documentation field of a CompletionItem.
 *
 * @return the supported MarkupKind[], may be null or undefined
 */
function getCompletionItemDocumentationFormat(capabilities) {
    return capabilities.textDocument
        && capabilities.textDocument.completion
        && capabilities.textDocument.completion.completionItem
        && capabilities.textDocument.completion.completionItem.documentationFormat;
}
function getHoverContentFormat(capabilities) {
    return capabilities.textDocument
        && capabilities.textDocument.hover
        && capabilities.textDocument.hover.contentFormat;
}
function getLineFoldingOnly(capabilities) {
    return capabilities.textDocument
        && capabilities.textDocument.foldingRange
        && capabilities.textDocument.foldingRange.lineFoldingOnly;
}
function getRangeLimit(capabilities) {
    let rangeLimit = capabilities.textDocument
        && capabilities.textDocument.foldingRange
        && capabilities.textDocument.foldingRange.rangeLimit;
    if (rangeLimit === null || rangeLimit === undefined || typeof rangeLimit === "boolean" || isNaN(rangeLimit)) {
        rangeLimit = Number.MAX_VALUE;
    }
    else if (typeof rangeLimit !== "number") {
        // isNaN === false and not a number, must be a string number, convert it
        rangeLimit = Number(rangeLimit);
    }
    return rangeLimit;
}
function setServiceCapabilities(capabilities) {
    service.setCapabilities({
        completion: {
            completionItem: {
                deprecatedSupport: supportsDeprecatedItems(capabilities),
                documentationFormat: getCompletionItemDocumentationFormat(capabilities),
                snippetSupport: supportsSnippets(capabilities)
            }
        },
        hover: {
            contentFormat: getHoverContentFormat(capabilities)
        },
        foldingRange: {
            lineFoldingOnly: getLineFoldingOnly(capabilities),
            rangeLimit: getRangeLimit(capabilities)
        }
    });
}
connection.onInitialized(() => {
    if (configurationSupport) {
        // listen for notification changes if the client supports workspace/configuration
        connection.client.register(node_1.DidChangeConfigurationNotification.type);
    }
});
connection.onInitialize((params) => {
    setServiceCapabilities(params.capabilities);
    applyEditSupport = params.capabilities.workspace && params.capabilities.workspace.applyEdit === true;
    documentChangesSupport = params.capabilities.workspace && params.capabilities.workspace.workspaceEdit && params.capabilities.workspace.workspaceEdit.documentChanges === true;
    configurationSupport = params.capabilities.workspace && params.capabilities.workspace.configuration === true;
    const renamePrepareSupport = params.capabilities.textDocument && params.capabilities.textDocument.rename && params.capabilities.textDocument.rename.prepareSupport === true;
    const semanticTokensSupport = params.capabilities.textDocument && params.capabilities.textDocument.semanticTokens;
    codeActionQuickFixSupport = supportsCodeActionQuickFixes(params.capabilities);
    return {
        capabilities: {
            textDocumentSync: node_1.TextDocumentSyncKind.Incremental,
            codeActionProvider: applyEditSupport,
            completionProvider: {
                resolveProvider: true,
                triggerCharacters: [
                    '=',
                    ' ',
                    '$',
                    '-',
                ]
            },
            executeCommandProvider: applyEditSupport ? {
                commands: [
                    dockerfile_language_service_1.CommandIds.LOWERCASE,
                    dockerfile_language_service_1.CommandIds.UPPERCASE,
                    dockerfile_language_service_1.CommandIds.EXTRA_ARGUMENT,
                    dockerfile_language_service_1.CommandIds.DIRECTIVE_TO_BACKSLASH,
                    dockerfile_language_service_1.CommandIds.DIRECTIVE_TO_BACKTICK,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_CHOWN,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_COPY_FROM,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_INTERVAL,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_RETRIES,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_START_PERIOD,
                    dockerfile_language_service_1.CommandIds.FLAG_TO_HEALTHCHECK_TIMEOUT,
                    dockerfile_language_service_1.CommandIds.CONVERT_TO_AS,
                    dockerfile_language_service_1.CommandIds.REMOVE_EMPTY_CONTINUATION_LINE
                ]
            } : undefined,
            documentFormattingProvider: true,
            documentRangeFormattingProvider: true,
            documentOnTypeFormattingProvider: {
                firstTriggerCharacter: '\\',
                moreTriggerCharacter: ['`']
            },
            hoverProvider: true,
            documentSymbolProvider: true,
            documentHighlightProvider: true,
            renameProvider: renamePrepareSupport ? {
                prepareProvider: true
            } : true,
            definitionProvider: true,
            signatureHelpProvider: {
                triggerCharacters: [
                    '-',
                    '[',
                    ',',
                    ' ',
                    '='
                ]
            },
            documentLinkProvider: {
                resolveProvider: true
            },
            semanticTokensProvider: semanticTokensSupport ? {
                full: {
                    delta: false
                },
                legend: {
                    tokenTypes: [
                        node_1.SemanticTokenTypes.keyword,
                        node_1.SemanticTokenTypes.comment,
                        node_1.SemanticTokenTypes.parameter,
                        node_1.SemanticTokenTypes.property,
                        node_1.SemanticTokenTypes.namespace,
                        node_1.SemanticTokenTypes.class,
                        node_1.SemanticTokenTypes.macro,
                        node_1.SemanticTokenTypes.string,
                        node_1.SemanticTokenTypes.variable,
                        node_1.SemanticTokenTypes.operator
                    ],
                    tokenModifiers: [
                        node_1.SemanticTokenModifiers.declaration,
                        node_1.SemanticTokenModifiers.definition,
                        node_1.SemanticTokenModifiers.deprecated
                    ]
                }
            } : undefined,
            foldingRangeProvider: true
        }
    };
});
function convertValidatorConfiguration(config) {
    let deprecatedMaintainer = dockerfile_utils_1.ValidationSeverity.WARNING;
    let directiveCasing = dockerfile_utils_1.ValidationSeverity.WARNING;
    let emptyContinuationLine = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionCasing = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionCmdMultiple = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionEntrypointMultiple = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionHealthcheckMultiple = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionJSONInSingleQuotes = dockerfile_utils_1.ValidationSeverity.WARNING;
    let instructionWorkdirRelative = dockerfile_utils_1.ValidationSeverity.WARNING;
    if (config) {
        deprecatedMaintainer = getSeverity(config.deprecatedMaintainer);
        directiveCasing = getSeverity(config.directiveCasing);
        emptyContinuationLine = getSeverity(config.emptyContinuationLine);
        instructionCasing = getSeverity(config.instructionCasing);
        instructionCmdMultiple = getSeverity(config.instructionCmdMultiple);
        instructionEntrypointMultiple = getSeverity(config.instructionEntrypointMultiple);
        instructionHealthcheckMultiple = getSeverity(config.instructionHealthcheckMultiple);
        instructionJSONInSingleQuotes = getSeverity(config.instructionJSONInSingleQuotes);
        instructionWorkdirRelative = getSeverity(config.instructionWorkdirRelative);
    }
    return {
        deprecatedMaintainer,
        directiveCasing,
        emptyContinuationLine,
        instructionCasing,
        instructionCmdMultiple,
        instructionEntrypointMultiple,
        instructionHealthcheckMultiple,
        instructionJSONInSingleQuotes,
        instructionWorkdirRelative
    };
}
function validateTextDocument(textDocument) {
    if (configurationSupport) {
        getValidatorConfiguration(textDocument.uri).then((config) => {
            const fileSettings = convertValidatorConfiguration(config);
            const diagnostics = service.validate(textDocument.getText(), fileSettings);
            connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
        });
    }
    else {
        const diagnostics = service.validate(textDocument.getText(), validatorSettings);
        connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
    }
}
function getSeverity(severity) {
    switch (severity) {
        case "ignore":
            return dockerfile_utils_1.ValidationSeverity.IGNORE;
        case "warning":
            return dockerfile_utils_1.ValidationSeverity.WARNING;
        case "error":
            return dockerfile_utils_1.ValidationSeverity.ERROR;
    }
    return null;
}
function getFormatterConfiguration(resource) {
    let result = formatterConfigurations.get(resource);
    if (!result) {
        result = connection.workspace.getConfiguration({ section: "docker.languageserver.formatter", scopeUri: resource });
        formatterConfigurations.set(resource, result);
    }
    return result;
}
/**
 * Gets the validation configuration that pertains to the specified resource.
 *
 * @param resource the interested resource
 * @return the configuration to use to validate the interested resource
 */
function getValidatorConfiguration(resource) {
    let result = validatorConfigurations.get(resource);
    if (!result) {
        result = connection.workspace.getConfiguration({ section: "docker.languageserver.diagnostics", scopeUri: resource });
        validatorConfigurations.set(resource, result);
    }
    return result;
}
// listen for notifications when the client's configuration has changed
connection.onNotification(node_1.DidChangeConfigurationNotification.type, () => {
    refreshConfigurations();
});
function getConfigurationItems(sectionName) {
    // store all the URIs that need to be refreshed
    const configurationItems = [];
    for (const uri in documents) {
        configurationItems.push({ section: sectionName, scopeUri: uri });
    }
    return configurationItems;
}
function refreshFormatterConfigurations() {
    // store all the URIs that need to be refreshed
    const settingsRequest = getConfigurationItems("docker.languageserver.formatter");
    // clear the cache
    formatterConfigurations.clear();
    // ask the workspace for the configurations
    connection.workspace.getConfiguration(settingsRequest).then((settings) => {
        for (let i = 0; i < settings.length; i++) {
            const resource = settingsRequest[i].scopeUri;
            // a value might have been stored already, use it instead and ignore this one if so
            if (settings[i] && !formatterConfigurations.has(resource)) {
                formatterConfigurations.set(resource, Promise.resolve(settings[i]));
            }
        }
    });
}
function refreshValidatorConfigurations() {
    // store all the URIs that need to be refreshed
    const settingsRequest = getConfigurationItems("docker.languageserver.diagnostics");
    // clear the cache
    validatorConfigurations.clear();
    // ask the workspace for the configurations
    connection.workspace.getConfiguration(settingsRequest).then((values) => {
        const toRevalidate = [];
        for (let i = 0; i < values.length; i++) {
            const resource = settingsRequest[i].scopeUri;
            // a value might have been stored already, use it instead and ignore this one if so
            if (values[i] && !validatorConfigurations.has(resource)) {
                validatorConfigurations.set(resource, Promise.resolve(values[i]));
                toRevalidate.push(resource);
            }
        }
        for (const resource of toRevalidate) {
            validateTextDocument(documents[resource]);
        }
    });
}
/**
 * Wipes and reloads the internal cache of configurations.
 */
function refreshConfigurations() {
    refreshFormatterConfigurations();
    refreshValidatorConfigurations();
}
connection.onDidChangeConfiguration((change) => {
    if (configurationSupport) {
        refreshConfigurations();
    }
    else {
        let settings = change.settings;
        if (settings.docker && settings.docker.languageserver) {
            if (settings.docker.languageserver.diagnostics) {
                validatorSettings = convertValidatorConfiguration(settings.docker.languageserver.diagnostics);
            }
            if (settings.docker.languageserver.formatter) {
                formatterConfiguration = settings.docker.languageserver.formatter;
            }
        }
        else {
            formatterConfiguration = null;
            validatorSettings = convertValidatorConfiguration(null);
        }
        // validate all the documents again
        Object.keys(documents).forEach((key) => {
            validateTextDocument(documents[key]);
        });
    }
});
connection.onCompletion((textDocumentPosition) => {
    return getDocument(textDocumentPosition.textDocument.uri).then((document) => {
        if (document) {
            return service.computeCompletionItems(document.getText(), textDocumentPosition.position);
        }
        return null;
    });
});
connection.onSignatureHelp((textDocumentPosition) => {
    return getDocument(textDocumentPosition.textDocument.uri).then((document) => {
        if (document !== null) {
            return service.computeSignatureHelp(document.getText(), textDocumentPosition.position);
        }
        return {
            signatures: [],
            activeSignature: null,
            activeParameter: null,
        };
    });
});
connection.onCompletionResolve((item) => {
    return service.resolveCompletionItem(item);
});
connection.onHover((textDocumentPosition) => {
    return getDocument(textDocumentPosition.textDocument.uri).then((document) => {
        if (document) {
            return service.computeHover(document.getText(), textDocumentPosition.position);
        }
        return null;
    });
});
connection.onDocumentHighlight((textDocumentPosition) => {
    return getDocument(textDocumentPosition.textDocument.uri).then((document) => {
        if (document) {
            return service.computeHighlightRanges(document.getText(), textDocumentPosition.position);
        }
        return [];
    });
});
connection.onCodeAction((codeActionParams) => {
    if (applyEditSupport && codeActionParams.context.diagnostics.length > 0) {
        let commands = service.computeCodeActions(codeActionParams.textDocument, codeActionParams.range, codeActionParams.context);
        if (codeActionQuickFixSupport) {
            return getDocument(codeActionParams.textDocument.uri).then((document) => {
                let codeActions = [];
                for (let command of commands) {
                    let codeAction = {
                        title: command.title,
                        kind: node_1.CodeActionKind.QuickFix
                    };
                    let edit = computeWorkspaceEdit(codeActionParams.textDocument.uri, document, command.command, command.arguments);
                    if (edit) {
                        codeAction.edit = edit;
                    }
                    codeActions.push(codeAction);
                }
                return codeActions;
            });
        }
        return commands;
    }
    return [];
});
function computeWorkspaceEdit(uri, document, command, args) {
    let edits = service.computeCommandEdits(document.getText(), command, args);
    if (edits) {
        if (documentChangesSupport) {
            let identifier = node_1.VersionedTextDocumentIdentifier.create(uri, document.version);
            return {
                documentChanges: [
                    node_1.TextDocumentEdit.create(identifier, edits)
                ]
            };
        }
        else {
            return {
                changes: {
                    [uri]: edits
                }
            };
        }
    }
    return null;
}
connection.onExecuteCommand((params) => {
    if (applyEditSupport) {
        let uri = params.arguments[0];
        getDocument(uri).then((document) => {
            if (document) {
                let workspaceEdit = computeWorkspaceEdit(uri, document, params.command, params.arguments);
                if (workspaceEdit) {
                    connection.workspace.applyEdit(workspaceEdit);
                }
            }
            return null;
        });
    }
});
connection.onDefinition((textDocumentPosition) => {
    return getDocument(textDocumentPosition.textDocument.uri).then((document) => {
        if (document) {
            return service.computeDefinition(textDocumentPosition.textDocument, document.getText(), textDocumentPosition.position);
        }
        return null;
    });
});
connection.onRenameRequest((params) => {
    return getDocument(params.textDocument.uri).then((document) => {
        if (document) {
            let edits = service.computeRename(params.textDocument, document.getText(), params.position, params.newName);
            return {
                changes: {
                    [params.textDocument.uri]: edits
                }
            };
        }
        return null;
    });
});
connection.onPrepareRename((params) => {
    return getDocument(params.textDocument.uri).then((document) => {
        if (document) {
            return service.prepareRename(document.getText(), params.position);
        }
        return null;
    });
});
connection.onDocumentSymbol((documentSymbolParams) => {
    return getDocument(documentSymbolParams.textDocument.uri).then((document) => {
        if (document) {
            return service.computeSymbols(documentSymbolParams.textDocument, document.getText());
        }
        return [];
    });
});
connection.onDocumentFormatting((documentFormattingParams) => {
    return getDocument(documentFormattingParams.textDocument.uri).then((document) => {
        if (configurationSupport) {
            return getFormatterConfiguration(document.uri).then((configuration) => {
                if (document) {
                    const options = documentFormattingParams.options;
                    options.ignoreMultilineInstructions = configuration !== null && configuration.ignoreMultilineInstructions;
                    return service.format(document.getText(), options);
                }
                return [];
            });
        }
        if (document) {
            const options = documentFormattingParams.options;
            options.ignoreMultilineInstructions = formatterConfiguration !== null && formatterConfiguration.ignoreMultilineInstructions;
            return service.format(document.getText(), options);
        }
        return [];
    });
});
connection.onDocumentRangeFormatting((rangeFormattingParams) => {
    return getDocument(rangeFormattingParams.textDocument.uri).then((document) => {
        if (configurationSupport) {
            return getFormatterConfiguration(document.uri).then((configuration) => {
                if (document) {
                    const options = rangeFormattingParams.options;
                    options.ignoreMultilineInstructions = configuration !== null && configuration.ignoreMultilineInstructions;
                    return service.formatRange(document.getText(), rangeFormattingParams.range, options);
                }
                return [];
            });
        }
        if (document) {
            const options = rangeFormattingParams.options;
            options.ignoreMultilineInstructions = formatterConfiguration !== null && formatterConfiguration.ignoreMultilineInstructions;
            return service.formatRange(document.getText(), rangeFormattingParams.range, rangeFormattingParams.options);
        }
        return [];
    });
});
connection.onDocumentOnTypeFormatting((onTypeFormattingParams) => {
    return getDocument(onTypeFormattingParams.textDocument.uri).then((document) => {
        if (configurationSupport) {
            return getFormatterConfiguration(document.uri).then((configuration) => {
                if (document) {
                    const options = onTypeFormattingParams.options;
                    options.ignoreMultilineInstructions = configuration !== null && configuration.ignoreMultilineInstructions;
                    return service.formatOnType(document.getText(), onTypeFormattingParams.position, onTypeFormattingParams.ch, options);
                }
                return [];
            });
        }
        if (document) {
            const options = onTypeFormattingParams.options;
            options.ignoreMultilineInstructions = formatterConfiguration !== null && formatterConfiguration.ignoreMultilineInstructions;
            return service.formatOnType(document.getText(), onTypeFormattingParams.position, onTypeFormattingParams.ch, onTypeFormattingParams.options);
        }
        return [];
    });
});
connection.onDocumentLinks((documentLinkParams) => {
    return getDocument(documentLinkParams.textDocument.uri).then((document) => {
        if (document) {
            return service.computeLinks(document.getText());
        }
        return [];
    });
});
connection.onDocumentLinkResolve((documentLink) => {
    return service.resolveLink(documentLink);
});
connection.onFoldingRanges((foldingRangeParams) => {
    return getDocument(foldingRangeParams.textDocument.uri).then((document) => {
        if (document) {
            return service.computeFoldingRanges(document.getText());
        }
        return [];
    });
});
connection.onDidOpenTextDocument((didOpenTextDocumentParams) => {
    let document = vscode_languageserver_textdocument_1.TextDocument.create(didOpenTextDocumentParams.textDocument.uri, didOpenTextDocumentParams.textDocument.languageId, didOpenTextDocumentParams.textDocument.version, didOpenTextDocumentParams.textDocument.text);
    documents[didOpenTextDocumentParams.textDocument.uri] = document;
    validateTextDocument(document);
});
connection.languages.semanticTokens.on((semanticTokenParams) => {
    return getDocument(semanticTokenParams.textDocument.uri).then((document) => {
        if (document) {
            return service.computeSemanticTokens(document.getText());
        }
        return {
            data: []
        };
    });
});
connection.onDidChangeTextDocument((didChangeTextDocumentParams) => {
    let document = documents[didChangeTextDocumentParams.textDocument.uri];
    let buffer = document.getText();
    let content = buffer;
    let changes = didChangeTextDocumentParams.contentChanges;
    for (let i = 0; i < changes.length; i++) {
        const change = changes[i];
        if (!change.range && !change.rangeLength) {
            // no ranges defined, the text is the entire document then
            buffer = change.text;
            document = vscode_languageserver_textdocument_1.TextDocument.create(didChangeTextDocumentParams.textDocument.uri, document.languageId, didChangeTextDocumentParams.textDocument.version, buffer);
            break;
        }
        let offset = document.offsetAt(change.range.start);
        let end = null;
        if (change.range.end) {
            end = document.offsetAt(change.range.end);
        }
        else {
            end = offset + change.rangeLength;
        }
        buffer = buffer.substring(0, offset) + change.text + buffer.substring(end);
        document = vscode_languageserver_textdocument_1.TextDocument.create(didChangeTextDocumentParams.textDocument.uri, document.languageId, didChangeTextDocumentParams.textDocument.version, buffer);
    }
    documents[didChangeTextDocumentParams.textDocument.uri] = document;
    if (content !== buffer) {
        validateTextDocument(document);
    }
});
connection.onDidCloseTextDocument((didCloseTextDocumentParams) => {
    validatorConfigurations.delete(didCloseTextDocumentParams.textDocument.uri);
    connection.sendDiagnostics({ uri: didCloseTextDocumentParams.textDocument.uri, diagnostics: [] });
    delete documents[didCloseTextDocumentParams.textDocument.uri];
});
// setup complete, start listening for a client connection
connection.listen();
//# sourceMappingURL=server.js.map