"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeScriptVersionProvider = exports.MODULE_FOLDERS = exports.TypeScriptVersion = void 0;
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const which_1 = __importDefault(require("which"));
const pkg_up_1 = __importDefault(require("pkg-up"));
const api_1 = __importDefault(require("./api"));
const modules_resolver_1 = require("./modules-resolver");
class TypeScriptVersion {
    constructor(source, path, _pathLabel, logger) {
        this.source = source;
        this.path = path;
        this._pathLabel = _pathLabel;
        this.logger = logger;
        this._api = null;
    }
    get tscPath() {
        return path_1.default.resolve(this.path, '../bin/tsc');
    }
    get tsServerPath() {
        return path_1.default.resolve(this.path, 'tsserver.js');
    }
    get pathLabel() {
        return typeof this._pathLabel === 'undefined' ? this.path : this._pathLabel;
    }
    get isValid() {
        return this.version !== null;
    }
    get version() {
        if (this._api) {
            return this._api;
        }
        this._api = this.getTypeScriptVersion(this.tsServerPath);
        return this._api;
    }
    get versionString() {
        const version = this.version;
        return version ? version.displayName : null;
    }
    getTypeScriptVersion(serverPath) {
        var _a, _b, _c, _d, _e, _f, _g, _h;
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Resolving TypeScript version from path "${serverPath}"...`);
        if (!fs_1.default.existsSync(serverPath)) {
            (_b = this.logger) === null || _b === void 0 ? void 0 : _b.info('Server path does not exist on disk');
            return null;
        }
        const p = serverPath.split(path_1.default.sep);
        if (p.length <= 2) {
            (_c = this.logger) === null || _c === void 0 ? void 0 : _c.info('Server path is invalid (has less than two path components).');
            return null;
        }
        const p2 = p.slice(0, -2);
        const modulePath = p2.join(path_1.default.sep);
        let fileName = path_1.default.join(modulePath, 'package.json');
        if (!fs_1.default.existsSync(fileName)) {
            // Special case for ts dev versions
            if (path_1.default.basename(modulePath) === 'built') {
                fileName = path_1.default.join(modulePath, '..', 'package.json');
            }
        }
        if (!fs_1.default.existsSync(fileName)) {
            (_d = this.logger) === null || _d === void 0 ? void 0 : _d.info(`Failed to find package.json at path "${fileName}"`);
            return null;
        }
        (_e = this.logger) === null || _e === void 0 ? void 0 : _e.info(`Reading version from package.json at "${fileName}"`);
        const contents = fs_1.default.readFileSync(fileName).toString();
        let desc = null;
        try {
            desc = JSON.parse(contents);
        }
        catch (err) {
            (_f = this.logger) === null || _f === void 0 ? void 0 : _f.info('Failed parsing contents of package.json.');
            return null;
        }
        if (!desc || !desc.version) {
            (_g = this.logger) === null || _g === void 0 ? void 0 : _g.info('Failed reading version number from package.json.');
            return null;
        }
        (_h = this.logger) === null || _h === void 0 ? void 0 : _h.info(`Resolved TypeScript version to "${desc.version}"`);
        return api_1.default.fromVersionString(desc.version);
    }
}
exports.TypeScriptVersion = TypeScriptVersion;
exports.MODULE_FOLDERS = ['node_modules/typescript/lib', '.vscode/pnpify/typescript/lib', '.yarn/sdks/typescript/lib'];
class TypeScriptVersionProvider {
    constructor(configuration, logger) {
        this.configuration = configuration;
        this.logger = logger;
    }
    getUserSettingVersion() {
        var _a, _b, _c, _d, _e, _f;
        const { tsserverPath } = this.configuration || {};
        if (!tsserverPath) {
            return null;
        }
        (_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Resolving user-provided tsserver path "${tsserverPath}"...`);
        let resolvedPath = tsserverPath;
        // Resolve full path to the binary if path is not absolute.
        if (!path_1.default.isAbsolute(resolvedPath)) {
            const binaryPath = which_1.default.sync(tsserverPath, { nothrow: true });
            if (binaryPath) {
                resolvedPath = binaryPath;
            }
            (_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Non-absolute tsserver path resolved to "${binaryPath ? resolvedPath : '<failed>'}"`);
        }
        // Resolve symbolic link.
        let stat = fs_1.default.lstatSync(resolvedPath, { throwIfNoEntry: false });
        if (stat === null || stat === void 0 ? void 0 : stat.isSymbolicLink()) {
            resolvedPath = fs_1.default.realpathSync(resolvedPath);
            (_c = this.logger) === null || _c === void 0 ? void 0 : _c.info(`Symbolic link tsserver path resolved to "${resolvedPath}"`);
        }
        // Get directory path
        stat = fs_1.default.lstatSync(resolvedPath, { throwIfNoEntry: false });
        if (stat === null || stat === void 0 ? void 0 : stat.isFile()) {
            resolvedPath = path_1.default.dirname(resolvedPath);
            (_d = this.logger) === null || _d === void 0 ? void 0 : _d.info(`Resolved directory path from a file path: ${resolvedPath}`);
        }
        // Resolve path to the "lib" dir.
        try {
            const packageJsonPath = pkg_up_1.default.sync({ cwd: resolvedPath });
            (_e = this.logger) === null || _e === void 0 ? void 0 : _e.info(`Resolved package.json location: "${packageJsonPath}"`);
            if (packageJsonPath) {
                resolvedPath = path_1.default.join(path_1.default.dirname(packageJsonPath), 'lib');
                (_f = this.logger) === null || _f === void 0 ? void 0 : _f.info(`Assumed tsserver lib location: "${resolvedPath}"`);
            }
        }
        catch (_g) {
            // ignore
        }
        return new TypeScriptVersion("user-setting" /* UserSetting */, resolvedPath, undefined, this.logger);
    }
    getWorkspaceVersion(workspaceFolders) {
        for (const p of workspaceFolders) {
            const libFolder = (0, modules_resolver_1.findPathToModule)(p, exports.MODULE_FOLDERS);
            if (libFolder) {
                const version = new TypeScriptVersion("workspace" /* Workspace */, libFolder);
                if (version.isValid) {
                    return version;
                }
            }
        }
        return null;
    }
    bundledVersion() {
        try {
            const file = require.resolve('typescript');
            const bundledVersion = new TypeScriptVersion("bundled" /* Bundled */, path_1.default.dirname(file), '');
            return bundledVersion;
        }
        catch (e) {
            // window.showMessage('Bundled typescript module not found', 'error');
            return null;
        }
    }
}
exports.TypeScriptVersionProvider = TypeScriptVersionProvider;
//# sourceMappingURL=versionProvider.js.map