UNPKG

coc.nvim

Version:

LSP based intellisense engine for neovim & vim8.

159 lines 7.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const child_process_1 = require("child_process"); const fs_1 = tslib_1.__importDefault(require("fs")); const mkdirp_1 = tslib_1.__importDefault(require("mkdirp")); const path_1 = tslib_1.__importDefault(require("path")); const rimraf_1 = tslib_1.__importDefault(require("rimraf")); const mv_1 = tslib_1.__importDefault(require("mv")); const semver_1 = tslib_1.__importDefault(require("semver")); const util_1 = require("util"); const workspace_1 = tslib_1.__importDefault(require("../workspace")); const download_1 = tslib_1.__importDefault(require("./download")); const fetch_1 = tslib_1.__importDefault(require("./fetch")); const rc_1 = tslib_1.__importDefault(require("rc")); const logger = require('../util/logger')('model-extension'); function registryUrl(scope = '') { const result = rc_1.default('npm', { registry: 'https://registry.npmjs.org/' }); const url = result[`${scope}:registry`] || result.config_registry || result.registry; return url.slice(-1) === '/' ? url : `${url}/`; } class ExtensionManager { constructor(root) { this.root = root; this.checked = false; } checkFolder() { if (this.checked) return; this.checked = true; let { root } = this; mkdirp_1.default.sync(root); mkdirp_1.default.sync(path_1.default.join(root, 'node_modules/.cache')); } async getInfo(npm, name) { if (name.startsWith('https:')) return await this.getInfoFromUri(name); let url = `${registryUrl()}/${name}`; let res = await fetch_1.default(url); let latest = res['versions'][res['dist-tags']['latest']]; return { 'dist.tarball': latest['dist']['tarball'], 'engines.coc': latest['engines'] && latest['engines']['coc'], version: latest['version'], name: res.name }; } async removeFolder(folder) { if (fs_1.default.existsSync(folder)) { let stat = await util_1.promisify(fs_1.default.lstat)(folder); if (stat.isSymbolicLink()) { await util_1.promisify(fs_1.default.unlink)(folder); } else { await util_1.promisify(rimraf_1.default)(folder, { glob: false }); } } } async _install(npm, def, info, onMessage) { let tmpFolder = await util_1.promisify(fs_1.default.mkdtemp)(path_1.default.join(this.root, 'node_modules/.cache', `${info.name}-`)); let url = info['dist.tarball']; onMessage(`Downloading from ${url}`); await download_1.default(url, { dest: tmpFolder }); let content = await util_1.promisify(fs_1.default.readFile)(path_1.default.join(tmpFolder, 'package.json'), 'utf8'); let { dependencies } = JSON.parse(content); if (dependencies && Object.keys(dependencies).length) { onMessage(`Installing dependencies.`); let p = new Promise((resolve, reject) => { let args = ['install', '--ignore-scripts', '--no-lockfile', '--no-bin-links', '--production']; const child = child_process_1.spawn(npm, args, { cwd: tmpFolder }); child.on('error', reject); child.on('exit', resolve); }); await p; } let jsonFile = path_1.default.join(this.root, 'package.json'); let obj = JSON.parse(fs_1.default.readFileSync(jsonFile, 'utf8')); obj.dependencies = obj.dependencies || {}; if (/^https?:/.test(def)) { obj.dependencies[info.name] = def; } else { obj.dependencies[info.name] = '>=' + info.version; } fs_1.default.writeFileSync(jsonFile, JSON.stringify(obj, null, 2), { encoding: 'utf8' }); onMessage(`Moving to new folder.`); let folder = path_1.default.join(this.root, 'node_modules', info.name); await this.removeFolder(folder); await util_1.promisify(mv_1.default)(tmpFolder, folder, { mkdirp: true }); } async install(npm, def) { this.checkFolder(); logger.info(`Using npm from: ${npm}`); logger.info(`Loading info of ${def}.`); let info = await this.getInfo(npm, def); if (info.error) { let { code, summary } = info.error; let msg = code == 'E404' ? `module ${def} not exists!` : summary; throw new Error(msg); } let { name } = info; let required = info['engines.coc'] ? info['engines.coc'].replace(/^\^/, '>=') : ''; if (required && !semver_1.default.satisfies(workspace_1.default.version, required)) { throw new Error(`${name} ${info.version} requires coc.nvim >= ${required}, please update coc.nvim.`); } await this._install(npm, def, info, msg => { logger.info(msg); }); workspace_1.default.showMessage(`Installed extension: ${name}`, 'more'); logger.info(`Installed extension: ${name}`); return name; } async update(npm, name, uri) { this.checkFolder(); let folder = path_1.default.join(this.root, 'node_modules', name); let stat = await util_1.promisify(fs_1.default.lstat)(folder); if (stat.isSymbolicLink()) { logger.info(`skipped update of ${name}`); return false; } let version; if (fs_1.default.existsSync(path_1.default.join(folder, 'package.json'))) { let content = await util_1.promisify(fs_1.default.readFile)(path_1.default.join(folder, 'package.json'), 'utf8'); version = JSON.parse(content).version; } logger.info(`Loading info of ${name}.`); let info = await this.getInfo(npm, uri ? uri : name); if (info.error) return; if (version && info.version && semver_1.default.gte(version, info.version)) { logger.info(`Extension ${name} is up to date.`); return false; } let required = info['engines.coc'] ? info['engines.coc'].replace(/^\^/, '>=') : ''; if (required && !semver_1.default.satisfies(workspace_1.default.version, required)) { throw new Error(`${name} ${info.version} requires coc.nvim >= ${required}, please update coc.nvim.`); } await this._install(npm, uri ? uri : name, info, msg => { logger.info(msg); }); workspace_1.default.showMessage(`Updated extension: ${name} to ${info.version}`, 'more'); logger.info(`Update extension: ${name}`); return true; } async getInfoFromUri(uri) { if (uri.indexOf('github.com') == -1) return; uri = uri.replace(/\/$/, ''); let fileUrl = uri.replace('github.com', 'raw.githubusercontent.com') + '/master/package.json'; let content = await fetch_1.default(fileUrl); let obj = typeof content == 'string' ? JSON.parse(content) : content; return { 'dist.tarball': `${uri}/archive/master.tar.gz`, 'engines.coc': obj['engines'] ? obj['engines']['coc'] : undefined, name: obj.name, version: obj.version }; } } exports.default = ExtensionManager; //# sourceMappingURL=extension.js.map