UNPKG

smash-package-installer

Version:
128 lines (117 loc) 5.34 kB
/** * npm 包下载器 * * 变量命名提示: * (1)packageName:含有包名、版本号,比如:smash-shell@0.0.1 * (2)purePackageName:只含有包名 */ const path = require('path'); const Copier = require('smash-copy'); const Shell = require('smash-shell'); // 安装包时的默认选项 // https://www.npmjs.cn/cli/install/ const DEFAULT_OPTIONS = { saveProd: true, // saved in the dependencies. saveDev: false, // saved in the devDependencies. saveOptional: false, // saved in the optionalDependencies. noSave: false, // 默认安装目录为工作目录。 // 这个目录需要有package.json文件,不然会安装到项目的顶层的node_modules里。 installationDir: process.cwd(), }; class PackageInstaller { /** * 拆分名称与版本的方法 * @param {String} packageName 包名的类型总共有4种。 */ static splitPackageName(packageName) { // 这里支持的包的类型总有4种, // (1)'smash-cli' => arr = [ 'smash-cli' ] // (2.1)'smash-cli@^1.0.0' => arr = [ 'smash-cli', '^1.0.0' ] // (2.2)'smash-cli@*' => arr = [ 'smash-cli', '*' ] // (3)'@erye/smash-cli' => arr = [ '', 'erye/smash-cli' ] // (4)'@erye/smash-cli@1.0.0' => arr = [ '', 'erye/smash-cli', '1.0.0' ] const arr = packageName.split('@'); if (arr[0] == '') { // 数组首位是空,符合类型 3、4 arr[1] = `@${arr[1]}`; // 给第二位加上 @ 字符 arr.shift(); // 移除首位 } return { purePackageName: arr[0], version: arr[1] || '' }; } /** * 判断已经安装号是否可以使用。参数位置不能调换。 * * npm包的规则比较复杂: * * 这意味着安装最新版本的依赖包 * ~ 会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0 * ^ 会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0 * @param {String} wantedVersion 目标版本号 * @param {String} installedVersion 当前版本号 */ static isInstalledVersionUsable(wantedVersion, installedVersion) { let isUsable = false; // wantedVersion = installedVersion // wantedVersion = '' if (wantedVersion == installedVersion || wantedVersion == '') { isUsable = true; } // wantedVersion = '*' // wantedVersion = 'latest' else if (wantedVersion == '*' || wantedVersion == 'latest') { // 安装最新版本 isUsable = false; // 直接安装最新版本,不再做检查操作 } // wantedVersion = '~1.0.0' else if (wantedVersion.indexOf('~') == 0) { // 会匹配最近的小版本依赖包 let arr1 = wantedVersion.replace(/[\~\^]/, '').split('.'); // => ['1', '2', 'x'] let arr2 = installedVersion.replace(/[\~\^]/, '').split('.'); // => ['1', '2', 'x'] isUsable = arr1[0] == arr2[0] && arr1[1] == arr2[1]; // 1位、2位必须相等,3位人一直 } // wantedVersion = '^1.0.0' else if (wantedVersion.indexOf('^') == 0) { // 会匹配最新的大版本依赖包 let arr1 = wantedVersion.replace(/[\~\^]/, '').split('.'); // => ['1', 'x', 'x'] let arr2 = installedVersion.replace(/[\~\^]/, '').split('.'); // => ['1', 'x', 'x'] isUsable = arr1[0] == arr2[0]; // 1位必须相等,2位、3位任意值 } // wantedVersion = '1.0.0' ... else { isUsable = wantedVersion === installedVersion.replace(/^[\~\^]/, ''); } return isUsable; } /** * 在指定的目录创建一个空的package.json文件 * @param {String} dir */ static createEmptyPackageJson(dir) { const fileSrc = path.resolve(__dirname, './emptyPackage.json'); const fileDst = path.resolve(dir, './package.json'); return Copier.copySync(fileSrc, fileDst); } /** * 安装一个或者多个npm包到指定的目录下 * @param {String|Array} packageName 'store5',或者 ['store5', 'smash-copy'] */ static install(packageName, options) { if (packageName instanceof Array) { packageName = packageName.join(' '); } options = { ...DEFAULT_OPTIONS, ...options }; let command = `npm i ${packageName}`; if (options.saveProd) { command = `npm i ${packageName} --save`; } if (options.saveDev) { command = `npm i ${packageName} --save-dev`; } if (options.saveDev) { command = `npm i ${packageName} --save-optional`; } if (options.noSave) { command = `npm i ${packageName} --no-save`; } return Shell.execSync(command, { cwd: options.installationDir, }); } } module.exports = PackageInstaller;