UNPKG

t-comm

Version:

专业、稳定、纯粹的工具库

257 lines (254 loc) 11.1 kB
import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import _regeneratorRuntime from '@babel/runtime/regenerator'; import { _ as __awaiter } from '../tslib.es6-848120af.js'; import axios from 'axios'; import { getChildProcess } from '../nodejs/child_process.mjs'; /** * 判断包是否是腾讯内网包(@tencent 开头) * @param name 包名 * @returns 是否是 @tencent/xxx 风格的内网包 */ function isTencentInternalPackage(name) { return typeof name === 'string' && name.startsWith('@tencent/'); } /** * 解析 npm 包详情页地址。 * - `@tencent/xxx`:腾讯内网镜像 detail 页(mirrors.tencent.com 私有 npm,repo_id=537) * - 其他:npmjs.com 公网详情页 * * @param name 包名 * @returns 完整 URL * @example * * resolveNpmLink('t-comm') * // 'https://mirrors.tencent.com/#/private/npm/detail?repo_id=537&project_name=%40tencent%2Ft-comm' * * resolveNpmLink('lodash') * // 'https://npmjs.com/package/lodash' */ function resolveNpmLink(name) { if (!name) return ''; if (isTencentInternalPackage(name)) { return "https://mirrors.tencent.com/#/private/npm/detail?repo_id=537&project_name=".concat(encodeURIComponent(name)); } return "https://npmjs.com/package/".concat(name); } /** * 通过 `npm view <name> time --json` 拿到所有版本的发布时间, * 按时间倒序返回最近的 N 个版本号(跳过 created/modified 两个非版本号 key)。 * * 这样做的原因: * - version-tip 是在「发布完成后」调用的,registry 上已经存在新版本; * - `time` 字段记录每个版本的 ISO 发布时间,倒序就能依次拿到「新版本」「上一个版本」。 * * @param {string} name 包名 * @param {number} limit 取最近的几个版本,默认 2(新、旧各一个) * @returns {string[]} 版本号数组,按时间倒序;失败返回空数组 */ function getRecentVersions(name) { var limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2; try { var _getChildProcess = getChildProcess(), execSync = _getChildProcess.execSync; var out = execSync("npm view ".concat(name, " time --json"), { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 16 * 1024 * 1024 }); var time = JSON.parse(String(out).trim() || '{}'); return Object.keys(time).filter(function (v) { return v !== 'created' && v !== 'modified'; }).sort(function (a, b) { return new Date(time[b]).getTime() - new Date(time[a]).getTime(); }).slice(0, limit); } catch (e) { console.warn("[version-tip] \u83B7\u53D6\u5386\u53F2\u7248\u672C\u5931\u8D25\uFF1A".concat((e === null || e === void 0 ? void 0 : e.message) || e)); return []; } } /** * 通过 `npm pack --dry-run --json` 获取「即将发布」的新包体积。 * * 注意事项: * - 必须在项目根目录或正确的 cwd 下执行,否则会发错包。 * - 文件多时输出会撑爆默认 `maxBuffer`(1MB),这里设为 64MB。 * - `--loglevel=error` 用于压住 npm 警告,进一步减少缓冲区占用。 * * @param options.cwd 工作目录,默认 `process.cwd()` * @returns 新包体积。失败时返回全 0。 */ function getNewPackageSize() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _a, _b, _c, _d, _e; var empty = { tarballSize: 0, unpackedSize: 0, fileCount: 0 }; try { var _getChildProcess2 = getChildProcess(), execSync = _getChildProcess2.execSync; var out = execSync('npm pack --dry-run --json --loglevel=error', { cwd: options.cwd || process.cwd(), encoding: 'utf-8', stdio: ['ignore', 'pipe', 'pipe'], maxBuffer: 64 * 1024 * 1024 }); var arr = JSON.parse(String(out).trim()); var info = Array.isArray(arr) ? arr[0] : arr; return { tarballSize: (_a = info === null || info === void 0 ? void 0 : info.size) !== null && _a !== void 0 ? _a : 0, unpackedSize: (_b = info === null || info === void 0 ? void 0 : info.unpackedSize) !== null && _b !== void 0 ? _b : 0, fileCount: (_e = (_c = info === null || info === void 0 ? void 0 : info.entryCount) !== null && _c !== void 0 ? _c : (_d = info === null || info === void 0 ? void 0 : info.files) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0 }; } catch (e) { console.warn("[GEN VERSION TIP] \u83B7\u53D6\u65B0\u5305\u4F53\u79EF\u5931\u8D25\uFF1A".concat((e === null || e === void 0 ? void 0 : e.message) || e)); return empty; } } /** * 选择 registry:内网包走腾讯源,公网包走 npmjs.org */ function pickRegistry(name) { var registry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; if (registry) return registry.replace(/\/$/, ''); return isTencentInternalPackage(name) ? 'https://mirrors.tencent.com/npm' : 'https://registry.npmjs.org'; } /** * 把 scoped 包名编码为 registry 路径片段 * `@tencent/foo` -> `@tencent/foo`(斜杠不编码,scope/name 各自 encode) */ function encodePackageName() { var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; if (name.startsWith('@')) { var _name$slice$split = name.slice(1).split('/'), _name$slice$split2 = _slicedToArray(_name$slice$split, 2), scope = _name$slice$split2[0], _name$slice$split2$ = _name$slice$split2[1], sub = _name$slice$split2$ === void 0 ? '' : _name$slice$split2$; return "@".concat(encodeURIComponent(scope), "/").concat(encodeURIComponent(sub)); } return encodeURIComponent(name); } /** * 通过 registry 接口拿指定版本的包体积。 * 兼容字段: * - 腾讯源 mirrors.tencent.com:`dist.packageSize`(tarball 字节,可能无 unpackedSize) * - 公网 npm:`dist.size`(tarball) + `dist.unpackedSize`(解包大小) + `dist.fileCount` */ function getPackageSizeByVersion(name, version) { var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; var _a, _b, _c, _d, _e, _f, _g; return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var empty, registry, url, _yield$axios$get, data, dist, _t; return _regeneratorRuntime.wrap(function (_context) { while (1) switch (_context.prev = _context.next) { case 0: empty = { tarballSize: 0, unpackedSize: 0, fileCount: 0 }; if (!(!name || !version)) { _context.next = 1; break; } return _context.abrupt("return", empty); case 1: registry = pickRegistry(name, options.registry); url = "".concat(registry, "/").concat(encodePackageName(name), "/").concat(encodeURIComponent(version)); _context.prev = 2; _context.next = 3; return axios.get(url, { responseType: 'json', timeout: (_a = options.timeout) !== null && _a !== void 0 ? _a : 15000 }); case 3: _yield$axios$get = _context.sent; data = _yield$axios$get.data; dist = (_b = data === null || data === void 0 ? void 0 : data.dist) !== null && _b !== void 0 ? _b : {}; return _context.abrupt("return", { tarballSize: (_e = (_d = (_c = dist.packageSize) !== null && _c !== void 0 ? _c : dist.size) !== null && _d !== void 0 ? _d : dist.contentLength) !== null && _e !== void 0 ? _e : 0, unpackedSize: (_f = dist.unpackedSize) !== null && _f !== void 0 ? _f : 0, fileCount: (_g = dist.fileCount) !== null && _g !== void 0 ? _g : 0 }); case 4: _context.prev = 4; _t = _context["catch"](2); console.warn("[version-tip] \u83B7\u53D6 ".concat(name, "@").concat(version, " \u4F53\u79EF\u5931\u8D25\uFF1A").concat((_t === null || _t === void 0 ? void 0 : _t.message) || _t)); return _context.abrupt("return", empty); case 5: case "end": return _context.stop(); } }, _callee, null, [[2, 4]]); })); } /** * 收集 `PackageSizeInfo`: * - 从 `npm view <name> time` 拿到最近两个版本(新、旧) * - 分别请求 registry 拿两个版本的体积,对比生成 PackageSizeInfo * * 注意:本方法依赖「发布完成后」调用,新版本必须已经在 registry 上。 * * @param {object} appInfo package.json 内容,至少包含 name * @param {object} [options] * @param {string} [options.registry] 自定义 registry * @returns {Promise<import('t-comm').PackageSizeInfo>} */ function collectPackageSize(appInfo) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() { var name, _getRecentVersions, _getRecentVersions2, newVersion, oldVersion, _yield$Promise$all, _yield$Promise$all2, newPkg, oldPkg; return _regeneratorRuntime.wrap(function (_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: name = appInfo === null || appInfo === void 0 ? void 0 : appInfo.name; if (name) { _context2.next = 1; break; } return _context2.abrupt("return", { newSize: 0 }); case 1: _getRecentVersions = getRecentVersions(name, 2), _getRecentVersions2 = _slicedToArray(_getRecentVersions, 2), newVersion = _getRecentVersions2[0], oldVersion = _getRecentVersions2[1]; console.log("[version-tip] ".concat(name, " new=").concat(newVersion || '(none)', " old=").concat(oldVersion || '(none)')); if (newVersion) { _context2.next = 2; break; } return _context2.abrupt("return", { newSize: 0 }); case 2: _context2.next = 3; return Promise.all([getPackageSizeByVersion(name, newVersion, { registry: options.registry }), oldVersion ? getPackageSizeByVersion(name, oldVersion, { registry: options.registry }) : Promise.resolve({ tarballSize: 0, unpackedSize: 0, fileCount: 0 })]); case 3: _yield$Promise$all = _context2.sent; _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 2); newPkg = _yield$Promise$all2[0]; oldPkg = _yield$Promise$all2[1]; return _context2.abrupt("return", { oldSize: oldPkg.tarballSize, newSize: newPkg.tarballSize, oldUnpacked: oldPkg.unpackedSize, newUnpacked: newPkg.unpackedSize, fileCount: newPkg.fileCount }); case 4: case "end": return _context2.stop(); } }, _callee2); })); } export { collectPackageSize, getNewPackageSize, getPackageSizeByVersion, getRecentVersions, isTencentInternalPackage, resolveNpmLink };