"use strict";
/*
 * Copyright (C) 2017, 2018 TypeFox and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Range = exports.asPlainText = exports.asTagBodyText = exports.asTagDocumentation = exports.asTagsDocumentation = exports.asDocumentation = exports.asRange = exports.toDocumentHighlight = exports.toTextDocumentEdit = exports.toTextEdit = exports.toDiagnostic = exports.toSymbolKind = exports.toFileRangeRequestArgs = exports.toLocation = exports.toPosition = exports.normalizeFsPath = exports.normalizePath = exports.pathToUri = exports.uriToPath = void 0;
const lsp = __importStar(require("vscode-languageserver/node"));
const vscode_uri_1 = require("vscode-uri");
const RE_PATHSEP_WINDOWS = /\\/g;
function uriToPath(stringUri) {
    // Vim may send `zipfile:` URIs which tsserver with Yarn v2+ hook can handle. Keep as-is.
    // Example: zipfile:///foo/bar/baz.zip::path/to/module
    if (stringUri.startsWith('zipfile:')) {
        return stringUri;
    }
    const uri = vscode_uri_1.URI.parse(stringUri);
    if (uri.scheme !== 'file') {
        return undefined;
    }
    return normalizeFsPath(uri.fsPath);
}
exports.uriToPath = uriToPath;
function pathToUri(filepath, documents) {
    // Yarn v2+ hooks tsserver and sends `zipfile:` URIs for Vim. Keep as-is.
    // Example: zipfile:///foo/bar/baz.zip::path/to/module
    if (filepath.startsWith('zipfile:')) {
        return filepath;
    }
    const fileUri = vscode_uri_1.URI.file(filepath);
    const normalizedFilepath = normalizePath(fileUri.fsPath);
    const document = documents && documents.get(normalizedFilepath);
    return document ? document.uri : fileUri.toString();
}
exports.pathToUri = pathToUri;
/**
 * Normalizes the file system path.
 *
 * On systems other than Windows it should be an no-op.
 *
 * On Windows, an input path in a format like "C:/path/file.ts"
 * will be normalized to "c:/path/file.ts".
 */
function normalizePath(filePath) {
    const fsPath = vscode_uri_1.URI.file(filePath).fsPath;
    return normalizeFsPath(fsPath);
}
exports.normalizePath = normalizePath;
/**
 * Normalizes the path obtained through the "fsPath" property of the URI module.
 */
function normalizeFsPath(fsPath) {
    return fsPath.replace(RE_PATHSEP_WINDOWS, '/');
}
exports.normalizeFsPath = normalizeFsPath;
function currentVersion(filepath, documents) {
    const fileUri = vscode_uri_1.URI.file(filepath);
    const normalizedFilepath = normalizePath(fileUri.fsPath);
    const document = documents && documents.get(normalizedFilepath);
    return document ? document.version : null;
}
function toPosition(location) {
    return {
        line: location.line - 1,
        character: location.offset - 1
    };
}
exports.toPosition = toPosition;
function toLocation(fileSpan, documents) {
    return {
        uri: pathToUri(fileSpan.file, documents),
        range: {
            start: toPosition(fileSpan.start),
            end: toPosition(fileSpan.end)
        }
    };
}
exports.toLocation = toLocation;
function toFileRangeRequestArgs(file, range) {
    return {
        file,
        startLine: range.start.line + 1,
        startOffset: range.start.character + 1,
        endLine: range.end.line + 1,
        endOffset: range.end.character + 1
    };
}
exports.toFileRangeRequestArgs = toFileRangeRequestArgs;
const symbolKindsMapping = {
    'enum member': lsp.SymbolKind.Constant,
    'JSX attribute': lsp.SymbolKind.Property,
    'local class': lsp.SymbolKind.Class,
    'local function': lsp.SymbolKind.Function,
    'local var': lsp.SymbolKind.Variable,
    'type parameter': lsp.SymbolKind.Variable,
    alias: lsp.SymbolKind.Variable,
    class: lsp.SymbolKind.Class,
    const: lsp.SymbolKind.Constant,
    constructor: lsp.SymbolKind.Constructor,
    enum: lsp.SymbolKind.Enum,
    field: lsp.SymbolKind.Field,
    file: lsp.SymbolKind.File,
    function: lsp.SymbolKind.Function,
    getter: lsp.SymbolKind.Method,
    interface: lsp.SymbolKind.Interface,
    let: lsp.SymbolKind.Variable,
    method: lsp.SymbolKind.Method,
    module: lsp.SymbolKind.Module,
    parameter: lsp.SymbolKind.Variable,
    property: lsp.SymbolKind.Property,
    setter: lsp.SymbolKind.Method,
    var: lsp.SymbolKind.Variable
};
function toSymbolKind(tspKind) {
    return symbolKindsMapping[tspKind] || lsp.SymbolKind.Variable;
}
exports.toSymbolKind = toSymbolKind;
function toDiagnosticSeverity(category) {
    switch (category) {
        case 'error': return lsp.DiagnosticSeverity.Error;
        case 'warning': return lsp.DiagnosticSeverity.Warning;
        case 'suggestion': return lsp.DiagnosticSeverity.Hint;
        default: return lsp.DiagnosticSeverity.Error;
    }
}
function toDiagnostic(diagnostic, documents, publishDiagnosticsCapabilities) {
    const lspDiagnostic = {
        range: {
            start: toPosition(diagnostic.start),
            end: toPosition(diagnostic.end)
        },
        message: diagnostic.text,
        severity: toDiagnosticSeverity(diagnostic.category),
        code: diagnostic.code,
        source: diagnostic.source || 'typescript',
        relatedInformation: asRelatedInformation(diagnostic.relatedInformation, documents)
    };
    if (publishDiagnosticsCapabilities === null || publishDiagnosticsCapabilities === void 0 ? void 0 : publishDiagnosticsCapabilities.tagSupport) {
        lspDiagnostic.tags = getDiagnosticTags(diagnostic);
    }
    return lspDiagnostic;
}
exports.toDiagnostic = toDiagnostic;
function getDiagnosticTags(diagnostic) {
    const tags = [];
    if (diagnostic.reportsUnnecessary) {
        tags.push(lsp.DiagnosticTag.Unnecessary);
    }
    if (diagnostic.reportsDeprecated) {
        tags.push(lsp.DiagnosticTag.Deprecated);
    }
    return tags;
}
function asRelatedInformation(info, documents) {
    if (!info) {
        return undefined;
    }
    const result = [];
    for (const item of info) {
        const span = item.span;
        if (span) {
            result.push(lsp.DiagnosticRelatedInformation.create(toLocation(span, documents), item.message));
        }
    }
    return result;
}
function toTextEdit(edit) {
    return {
        range: {
            start: toPosition(edit.start),
            end: toPosition(edit.end)
        },
        newText: edit.newText
    };
}
exports.toTextEdit = toTextEdit;
function toTextDocumentEdit(change, documents) {
    return {
        textDocument: {
            uri: pathToUri(change.fileName, documents),
            version: currentVersion(change.fileName, documents)
        },
        edits: change.textChanges.map(c => toTextEdit(c))
    };
}
exports.toTextDocumentEdit = toTextDocumentEdit;
function toDocumentHighlight(item) {
    return item.highlightSpans.map(i => {
        return {
            kind: toDocumentHighlightKind(i.kind),
            range: {
                start: toPosition(i.start),
                end: toPosition(i.end)
            }
        };
    });
}
exports.toDocumentHighlight = toDocumentHighlight;
// copied because the protocol module is not available at runtime (js version).
var HighlightSpanKind;
(function (HighlightSpanKind) {
    HighlightSpanKind["none"] = "none";
    HighlightSpanKind["definition"] = "definition";
    HighlightSpanKind["reference"] = "reference";
    HighlightSpanKind["writtenReference"] = "writtenReference";
})(HighlightSpanKind || (HighlightSpanKind = {}));
function toDocumentHighlightKind(kind) {
    switch (kind) {
        case HighlightSpanKind.definition: return lsp.DocumentHighlightKind.Write;
        case HighlightSpanKind.reference:
        case HighlightSpanKind.writtenReference: return lsp.DocumentHighlightKind.Read;
        default: return lsp.DocumentHighlightKind.Text;
    }
}
function asRange(span) {
    return lsp.Range.create(Math.max(0, span.start.line - 1), Math.max(0, span.start.offset - 1), Math.max(0, span.end.line - 1), Math.max(0, span.end.offset - 1));
}
exports.asRange = asRange;
function asDocumentation(data) {
    let value = '';
    if (data.documentation) {
        value += asPlainText(data.documentation);
    }
    if (data.tags) {
        const tagsDocumentation = asTagsDocumentation(data.tags);
        if (tagsDocumentation) {
            value += '\n\n' + tagsDocumentation;
        }
    }
    return value.length ? {
        kind: lsp.MarkupKind.Markdown,
        value
    } : undefined;
}
exports.asDocumentation = asDocumentation;
function asTagsDocumentation(tags) {
    return tags.map(asTagDocumentation).join('  \n\n');
}
exports.asTagsDocumentation = asTagsDocumentation;
function asTagDocumentation(tag) {
    switch (tag.name) {
        case 'param': {
            if (!tag.text) {
                break;
            }
            const text = asPlainText(tag.text);
            const body = text.split(/^([\w.]+)\s*-?\s*/);
            if (body && body.length === 3) {
                const param = body[1];
                const doc = body[2];
                const label = `*@${tag.name}* \`${param}\``;
                if (!doc) {
                    return label;
                }
                return label + (doc.match(/\r\n|\n/g) ? '  \n' + doc : ` — ${doc}`);
            }
            break;
        }
    }
    // Generic tag
    const label = `*@${tag.name}*`;
    const text = asTagBodyText(tag);
    if (!text) {
        return label;
    }
    return label + (text.match(/\r\n|\n/g) ? '  \n' + text : ` — ${text}`);
}
exports.asTagDocumentation = asTagDocumentation;
function asTagBodyText(tag) {
    if (!tag.text) {
        return undefined;
    }
    const text = asPlainText(tag.text);
    switch (tag.name) {
        case 'example':
        case 'default':
            // Convert to markdown code block if it not already one
            if (text.match(/^\s*[~`]{3}/g)) {
                return text;
            }
            return '```\n' + text + '\n```';
    }
    return text;
}
exports.asTagBodyText = asTagBodyText;
function asPlainText(parts) {
    if (typeof parts === 'string') {
        return parts;
    }
    return parts.map(part => part.text).join('');
}
exports.asPlainText = asPlainText;
var Position;
(function (Position) {
    function Min(...positions) {
        if (!positions.length) {
            return undefined;
        }
        let result = positions.pop();
        for (const p of positions) {
            if (isBefore(p, result)) {
                result = p;
            }
        }
        return result;
    }
    Position.Min = Min;
    function isBefore(one, other) {
        if (one.line < other.line) {
            return true;
        }
        if (other.line < one.line) {
            return false;
        }
        return one.character < other.character;
    }
    Position.isBefore = isBefore;
    function Max(...positions) {
        if (!positions.length) {
            return undefined;
        }
        let result = positions.pop();
        for (const p of positions) {
            if (isAfter(p, result)) {
                result = p;
            }
        }
        return result;
    }
    Position.Max = Max;
    function isAfter(one, other) {
        return !isBeforeOrEqual(one, other);
    }
    Position.isAfter = isAfter;
    function isBeforeOrEqual(one, other) {
        if (one.line < other.line) {
            return true;
        }
        if (other.line < one.line) {
            return false;
        }
        return one.character <= other.character;
    }
    Position.isBeforeOrEqual = isBeforeOrEqual;
})(Position || (Position = {}));
var Range;
(function (Range) {
    function intersection(one, other) {
        const start = Position.Max(other.start, one.start);
        const end = Position.Min(other.end, one.end);
        if (Position.isAfter(start, end)) {
            // this happens when there is no overlap:
            // |-----|
            //          |----|
            return undefined;
        }
        return lsp.Range.create(start, end);
    }
    Range.intersection = intersection;
})(Range = exports.Range || (exports.Range = {}));
//# sourceMappingURL=protocol-translation.js.map