"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasTsExtensions = exports.toGeneratedSvelteComponentName = exports.offsetOfGeneratedComponentExport = exports.isGeneratedSvelteComponentName = exports.changeSvelteComponentName = exports.getDiagnosticTag = exports.isInScript = exports.convertToTextSpan = exports.getTsCheckComment = exports.mapSeverity = exports.scriptElementKindToCompletionItemKind = exports.symbolKindFromString = exports.getNearestWorkspaceUri = exports.isSubPath = exports.findTsConfigPath = exports.rangeToTextSpan = exports.hasNonZeroRange = exports.convertToLocationForReferenceOrDefinition = exports.convertToLocationRange = exports.convertRange = exports.ensureRealSvelteFilePath = exports.toVirtualSvelteFilePath = exports.toRealSvelteFilePath = exports.isVirtualSvelteFilePath = exports.isSvelteFilePath = exports.getScriptKindFromAttributes = exports.getExtensionFromScriptKind = exports.getScriptKindFromFileName = void 0;
const path_1 = require("path");
const typescript_1 = __importDefault(require("typescript"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../lib/documents");
const utils_1 = require("../../utils");
function getScriptKindFromFileName(fileName) {
    const ext = fileName.substr(fileName.lastIndexOf('.'));
    switch (ext.toLowerCase()) {
        case typescript_1.default.Extension.Js:
            return typescript_1.default.ScriptKind.JS;
        case typescript_1.default.Extension.Jsx:
            return typescript_1.default.ScriptKind.JSX;
        case typescript_1.default.Extension.Ts:
            return typescript_1.default.ScriptKind.TS;
        case typescript_1.default.Extension.Tsx:
            return typescript_1.default.ScriptKind.TSX;
        case typescript_1.default.Extension.Json:
            return typescript_1.default.ScriptKind.JSON;
        default:
            return typescript_1.default.ScriptKind.Unknown;
    }
}
exports.getScriptKindFromFileName = getScriptKindFromFileName;
function getExtensionFromScriptKind(kind) {
    switch (kind) {
        case typescript_1.default.ScriptKind.JSX:
            return typescript_1.default.Extension.Jsx;
        case typescript_1.default.ScriptKind.TS:
            return typescript_1.default.Extension.Ts;
        case typescript_1.default.ScriptKind.TSX:
            return typescript_1.default.Extension.Tsx;
        case typescript_1.default.ScriptKind.JSON:
            return typescript_1.default.Extension.Json;
        case typescript_1.default.ScriptKind.JS:
        default:
            return typescript_1.default.Extension.Js;
    }
}
exports.getExtensionFromScriptKind = getExtensionFromScriptKind;
function getScriptKindFromAttributes(attrs) {
    const type = attrs.lang || attrs.type;
    switch (type) {
        case 'ts':
        case 'typescript':
        case 'text/ts':
        case 'text/typescript':
            return typescript_1.default.ScriptKind.TSX;
        case 'javascript':
        case 'text/javascript':
        default:
            return typescript_1.default.ScriptKind.JSX;
    }
}
exports.getScriptKindFromAttributes = getScriptKindFromAttributes;
function isSvelteFilePath(filePath) {
    return filePath.endsWith('.svelte');
}
exports.isSvelteFilePath = isSvelteFilePath;
function isVirtualSvelteFilePath(filePath) {
    return filePath.endsWith('.svelte.ts');
}
exports.isVirtualSvelteFilePath = isVirtualSvelteFilePath;
function toRealSvelteFilePath(filePath) {
    return filePath.slice(0, -'.ts'.length);
}
exports.toRealSvelteFilePath = toRealSvelteFilePath;
function toVirtualSvelteFilePath(filePath) {
    return filePath.endsWith('.ts') ? filePath : filePath + '.ts';
}
exports.toVirtualSvelteFilePath = toVirtualSvelteFilePath;
function ensureRealSvelteFilePath(filePath) {
    return isVirtualSvelteFilePath(filePath) ? toRealSvelteFilePath(filePath) : filePath;
}
exports.ensureRealSvelteFilePath = ensureRealSvelteFilePath;
function convertRange(document, range) {
    return vscode_languageserver_1.Range.create(document.positionAt(range.start || 0), document.positionAt((range.start || 0) + (range.length || 0)));
}
exports.convertRange = convertRange;
function convertToLocationRange(snapshot, textSpan) {
    const range = (0, documents_1.mapRangeToOriginal)(snapshot, convertRange(snapshot, textSpan));
    mapUnmappedToTheStartOfFile(range);
    return range;
}
exports.convertToLocationRange = convertToLocationRange;
function convertToLocationForReferenceOrDefinition(snapshot, textSpan) {
    const location = (0, documents_1.mapLocationToOriginal)(snapshot, convertRange(snapshot, textSpan));
    mapUnmappedToTheStartOfFile(location.range);
    return location;
}
exports.convertToLocationForReferenceOrDefinition = convertToLocationForReferenceOrDefinition;
/**Some definition like the svelte component class definition don't exist in the original, so we map to 0,1*/
function mapUnmappedToTheStartOfFile(range) {
    if (range.start.line < 0) {
        range.start.line = 0;
        range.start.character = 1;
    }
    if (range.end.line < 0) {
        range.end = range.start;
    }
}
function hasNonZeroRange({ range }) {
    return (!!range &&
        (range.start.line !== range.end.line || range.start.character !== range.end.character));
}
exports.hasNonZeroRange = hasNonZeroRange;
function rangeToTextSpan(range, document) {
    const start = document.offsetAt(range.start);
    const end = document.offsetAt(range.end);
    return { start, length: end - start };
}
exports.rangeToTextSpan = rangeToTextSpan;
function findTsConfigPath(fileName, rootUris, fileExists, getCanonicalFileName) {
    const searchDir = (0, path_1.dirname)(fileName);
    const tsconfig = typescript_1.default.findConfigFile(searchDir, fileExists, 'tsconfig.json') || '';
    const jsconfig = typescript_1.default.findConfigFile(searchDir, fileExists, 'jsconfig.json') || '';
    // Prefer closest config file
    const config = tsconfig.length >= jsconfig.length ? tsconfig : jsconfig;
    // Don't return config files that exceed the current workspace context or cross a node_modules folder
    return !!config &&
        rootUris.some((rootUri) => isSubPath(rootUri, config, getCanonicalFileName)) &&
        !fileName
            .substring(config.length - 13)
            .split('/')
            .includes('node_modules')
        ? config
        : '';
}
exports.findTsConfigPath = findTsConfigPath;
function isSubPath(uri, possibleSubPath, getCanonicalFileName) {
    // URL escape codes are in upper-case
    // so getCanonicalFileName should be called after converting to file url
    return getCanonicalFileName((0, utils_1.pathToUrl)(possibleSubPath)).startsWith(getCanonicalFileName(uri));
}
exports.isSubPath = isSubPath;
function getNearestWorkspaceUri(workspaceUris, path, getCanonicalFileName) {
    return Array.from(workspaceUris)
        .sort((a, b) => b.length - a.length)
        .find((workspaceUri) => isSubPath(workspaceUri, path, getCanonicalFileName));
}
exports.getNearestWorkspaceUri = getNearestWorkspaceUri;
function symbolKindFromString(kind) {
    switch (kind) {
        case 'module':
            return vscode_languageserver_1.SymbolKind.Module;
        case 'class':
            return vscode_languageserver_1.SymbolKind.Class;
        case 'local class':
            return vscode_languageserver_1.SymbolKind.Class;
        case 'interface':
            return vscode_languageserver_1.SymbolKind.Interface;
        case 'enum':
            return vscode_languageserver_1.SymbolKind.Enum;
        case 'enum member':
            return vscode_languageserver_1.SymbolKind.Constant;
        case 'var':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'local var':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'function':
            return vscode_languageserver_1.SymbolKind.Function;
        case 'local function':
            return vscode_languageserver_1.SymbolKind.Function;
        case 'method':
            return vscode_languageserver_1.SymbolKind.Method;
        case 'getter':
            return vscode_languageserver_1.SymbolKind.Method;
        case 'setter':
            return vscode_languageserver_1.SymbolKind.Method;
        case 'property':
            return vscode_languageserver_1.SymbolKind.Property;
        case 'constructor':
            return vscode_languageserver_1.SymbolKind.Constructor;
        case 'parameter':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'type parameter':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'alias':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'let':
            return vscode_languageserver_1.SymbolKind.Variable;
        case 'const':
            return vscode_languageserver_1.SymbolKind.Constant;
        case 'JSX attribute':
            return vscode_languageserver_1.SymbolKind.Property;
        default:
            return vscode_languageserver_1.SymbolKind.Variable;
    }
}
exports.symbolKindFromString = symbolKindFromString;
function scriptElementKindToCompletionItemKind(kind) {
    switch (kind) {
        case typescript_1.default.ScriptElementKind.primitiveType:
        case typescript_1.default.ScriptElementKind.keyword:
            return vscode_languageserver_1.CompletionItemKind.Keyword;
        case typescript_1.default.ScriptElementKind.constElement:
            return vscode_languageserver_1.CompletionItemKind.Constant;
        case typescript_1.default.ScriptElementKind.letElement:
        case typescript_1.default.ScriptElementKind.variableElement:
        case typescript_1.default.ScriptElementKind.localVariableElement:
        case typescript_1.default.ScriptElementKind.alias:
            return vscode_languageserver_1.CompletionItemKind.Variable;
        case typescript_1.default.ScriptElementKind.memberVariableElement:
        case typescript_1.default.ScriptElementKind.memberGetAccessorElement:
        case typescript_1.default.ScriptElementKind.memberSetAccessorElement:
            return vscode_languageserver_1.CompletionItemKind.Field;
        case typescript_1.default.ScriptElementKind.functionElement:
            return vscode_languageserver_1.CompletionItemKind.Function;
        case typescript_1.default.ScriptElementKind.memberFunctionElement:
        case typescript_1.default.ScriptElementKind.constructSignatureElement:
        case typescript_1.default.ScriptElementKind.callSignatureElement:
        case typescript_1.default.ScriptElementKind.indexSignatureElement:
            return vscode_languageserver_1.CompletionItemKind.Method;
        case typescript_1.default.ScriptElementKind.enumElement:
            return vscode_languageserver_1.CompletionItemKind.Enum;
        case typescript_1.default.ScriptElementKind.moduleElement:
        case typescript_1.default.ScriptElementKind.externalModuleName:
            return vscode_languageserver_1.CompletionItemKind.Module;
        case typescript_1.default.ScriptElementKind.classElement:
        case typescript_1.default.ScriptElementKind.typeElement:
            return vscode_languageserver_1.CompletionItemKind.Class;
        case typescript_1.default.ScriptElementKind.interfaceElement:
            return vscode_languageserver_1.CompletionItemKind.Interface;
        case typescript_1.default.ScriptElementKind.warning:
        case typescript_1.default.ScriptElementKind.scriptElement:
            return vscode_languageserver_1.CompletionItemKind.File;
        case typescript_1.default.ScriptElementKind.directory:
            return vscode_languageserver_1.CompletionItemKind.Folder;
        case typescript_1.default.ScriptElementKind.string:
            return vscode_languageserver_1.CompletionItemKind.Constant;
    }
    return vscode_languageserver_1.CompletionItemKind.Property;
}
exports.scriptElementKindToCompletionItemKind = scriptElementKindToCompletionItemKind;
function mapSeverity(category) {
    switch (category) {
        case typescript_1.default.DiagnosticCategory.Error:
            return vscode_languageserver_1.DiagnosticSeverity.Error;
        case typescript_1.default.DiagnosticCategory.Warning:
            return vscode_languageserver_1.DiagnosticSeverity.Warning;
        case typescript_1.default.DiagnosticCategory.Suggestion:
            return vscode_languageserver_1.DiagnosticSeverity.Hint;
        case typescript_1.default.DiagnosticCategory.Message:
            return vscode_languageserver_1.DiagnosticSeverity.Information;
    }
    return vscode_languageserver_1.DiagnosticSeverity.Error;
}
exports.mapSeverity = mapSeverity;
// Matches comments that come before any non-comment content
const commentsRegex = /^(\s*\/\/.*\s*)*/;
// The following regex matches @ts-check or @ts-nocheck if:
// - must be @ts-(no)check
// - the comment which has @ts-(no)check can have any type of whitespace before it, but not other characters
// - what's coming after @ts-(no)check is irrelevant as long there is any kind of whitespace or line break, so this would be picked up, too: // @ts-check asdasd
// [ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]
// is just \s (a.k.a any whitespace character) without linebreak and vertical tab
const tsCheckRegex = /\/\/[ \t\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]*(@ts-(no)?check)($|\s)/;
/**
 * Returns `// @ts-check` or `// @ts-nocheck` if content starts with comments and has one of these
 * in its comments.
 */
function getTsCheckComment(str = '') {
    const comments = str.match(commentsRegex)?.[0];
    if (comments) {
        const tsCheck = comments.match(tsCheckRegex);
        if (tsCheck) {
            // second-last entry is the capturing group with the exact ts-check wording
            return `// ${tsCheck[tsCheck.length - 3]}${typescript_1.default.sys.newLine}`;
        }
    }
}
exports.getTsCheckComment = getTsCheckComment;
function convertToTextSpan(range, snapshot) {
    const start = snapshot.offsetAt(snapshot.getGeneratedPosition(range.start));
    const end = snapshot.offsetAt(snapshot.getGeneratedPosition(range.end));
    return {
        start,
        length: end - start
    };
}
exports.convertToTextSpan = convertToTextSpan;
function isInScript(position, snapshot) {
    return (0, documents_1.isInTag)(position, snapshot.scriptInfo) || (0, documents_1.isInTag)(position, snapshot.moduleScriptInfo);
}
exports.isInScript = isInScript;
function getDiagnosticTag(diagnostic) {
    const tags = [];
    if (diagnostic.reportsUnnecessary) {
        tags.push(vscode_languageserver_1.DiagnosticTag.Unnecessary);
    }
    if (diagnostic.reportsDeprecated) {
        tags.push(vscode_languageserver_1.DiagnosticTag.Deprecated);
    }
    return tags;
}
exports.getDiagnosticTag = getDiagnosticTag;
function changeSvelteComponentName(name) {
    return name.replace(/(\w+)__SvelteComponent_/, '$1');
}
exports.changeSvelteComponentName = changeSvelteComponentName;
const COMPONENT_SUFFIX = '__SvelteComponent_';
function isGeneratedSvelteComponentName(className) {
    return className.endsWith(COMPONENT_SUFFIX);
}
exports.isGeneratedSvelteComponentName = isGeneratedSvelteComponentName;
function offsetOfGeneratedComponentExport(snapshot) {
    return snapshot.getFullText().lastIndexOf(COMPONENT_SUFFIX);
}
exports.offsetOfGeneratedComponentExport = offsetOfGeneratedComponentExport;
function toGeneratedSvelteComponentName(className) {
    return className + COMPONENT_SUFFIX;
}
exports.toGeneratedSvelteComponentName = toGeneratedSvelteComponentName;
function hasTsExtensions(fileName) {
    return (fileName.endsWith(typescript_1.default.Extension.Dts) ||
        fileName.endsWith(typescript_1.default.Extension.Tsx) ||
        fileName.endsWith(typescript_1.default.Extension.Ts));
}
exports.hasTsExtensions = hasTsExtensions;
//# sourceMappingURL=utils.js.map