UNPKG

t-comm

Version:

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

1,854 lines (1,820 loc) 833 kB
import _typeof from '@babel/runtime/helpers/typeof'; import * as fs from 'fs'; import fs__default, { statSync, readFileSync as readFileSync$1, writeFileSync as writeFileSync$1 } from 'fs'; import * as path from 'path'; import path__default, { join } from 'path'; import axios from 'axios'; import { execSync, spawnSync } from 'child_process'; import * as os from 'os'; import { tmpdir } from 'os'; import * as http from 'http'; /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }; function parseOptions(options, key) { var _a; if (key === void 0) { key = 'msg'; } var innerOptions = {}; if (typeof options === 'string') { innerOptions = (_a = {}, _a[key] = options, _a); } else if (_typeof(options) === 'object') { innerOptions = options; } innerOptions = Object.keys(innerOptions).reduce(function (acc, item) { var value = innerOptions[item]; acc[item] = _typeof(value) === 'object' ? JSON.stringify(value) : value; return acc; }, {}); return innerOptions; } function aegisReportInfoV2(mAegisV2, options, method) { if (method === void 0) { method = 'info'; } if (!mAegisV2 || !options || !method) return; try { var innerOptions = parseOptions(options, 'msg'); mAegisV2[method](__assign({}, innerOptions)); } catch (err) { console.log('[reportInfo] error', err); } } function aegisReportErrorV2(mAegisV2, options) { return aegisReportInfoV2(mAegisV2, options, 'error'); } function aegisReportV2(mAegisV2, options) { return aegisReportInfoV2(mAegisV2, options, 'report'); } function aegisReportEventV2(mAegisV2, options) { if (!mAegisV2 || !options) return; try { var innerOptions = parseOptions(options, 'name'); if (!innerOptions.name) return; mAegisV2.reportEvent(__assign({}, innerOptions)); } catch (err) { console.log('[reportEvent] error', err); } } var IImportType; (function (IImportType) { IImportType["ImportSpecifier"] = "ImportSpecifier"; IImportType["ImportDefaultSpecifier"] = "ImportDefaultSpecifier"; IImportType["importNamespaceSpecifier"] = "ImportNamespaceSpecifier"; IImportType["FAKE"] = "FAKE"; })(IImportType || (IImportType = {})); function parseOneReplaceConfig(config) { if (typeof config === 'string') { return { sourceName: config, sourceType: IImportType.ImportSpecifier, targetName: config, targetType: IImportType.ImportSpecifier }; } if (Array.isArray(config)) { return { sourceName: config[0], sourceType: IImportType.ImportSpecifier, targetName: config[1] || config[0], targetType: IImportType.ImportSpecifier }; } return { sourceName: config.sourceName || '', sourceType: config.sourceType || IImportType.ImportSpecifier, targetName: config.targetName || config.sourceName || '', targetType: config.targetType || config.sourceType || IImportType.ImportSpecifier }; } /** * 解析替换配置 * * @param {Array<IReplaceConfig>} configList 配置列表 * @returns {array} 处理后的配置列表 * * @example * ```ts * parseReplaceConfig([{ * source: '', * target: '', * }]) * ``` */ function parseReplaceConfig(configList) { var result = configList.reduce(function (acc, item) { var importedList = item.importedList, source = item.source, target = item.target; var newSource = Array.isArray(source) ? source : [source]; var list = importedList.map(function (item) { return __assign({ source: newSource, target: target }, parseOneReplaceConfig(item)); }); if (!importedList.length) { acc.push(__assign(__assign({}, item), { source: newSource, sourceName: 'FAKE', targetName: 'FAKE', sourceType: IImportType.FAKE, targetType: IImportType.FAKE })); } else { acc.push.apply(acc, list); } return acc; }, []); var newResult = result.reduce(function (acc, item) { var source = item.source; var list = source.map(function (sourceItem) { return __assign(__assign({}, item), { source: sourceItem }); }); acc.push.apply(acc, list); return acc; }, []); return newResult; } /** * 替换引用 * * @param {string} content 输入内容 * @param {Array<IParsedConfigItem>} parsedConfigList 替换配置 * @param {string} keyword 提前返回关键词 * @returns {string} 处理后的内容 * * @example * ```ts * replaceDependencies('', [], '@tx/pmd-vue') * ``` */ function replaceDependencies(content, parsedConfigList, keyword) { var parser = require('@babel/parser'); var traverse = require('@babel/traverse')["default"]; var generator = require('@babel/generator'); var replaced = false; var ast = parser.parse(content, { // 不加这个配置,报错:SyntaxError: 'import' and 'export' may appear only with 'sourceType: "module"' sourceType: 'module', plugins: ['typescript'] }); traverse(ast, { ImportDeclaration: function ImportDeclaration(path) { var sourceValue = path.node.source.value; var importedList = path.node.specifiers.map(function (item) { var _a; var type = item.type; return { type: type, local: item.local.name, imported: ((_a = item.imported) === null || _a === void 0 ? void 0 : _a.name) || '' }; }); if (sourceValue.includes(keyword)) return; var target = getTarget(sourceValue, importedList, parsedConfigList); target.forEach(function (item) { path.insertAfter(item); }); if (target.length) { path.remove(); replaced = true; } } }); var output = generator["default"](ast, {}); if (replaced) { return output.code; } return content; } function localFlatten(list) { return list.reduce(function (acc, current) { var target = current.target; if (acc[target]) { acc[target].push(current); } else { acc[target] = [current]; } return acc; }, {}); } function getTarget(originSource, originImportedList, parsedConfigList) { if (!originImportedList.length) { var foundItem = parsedConfigList.find(function (item) { return item.source === originSource; }); if (!(foundItem === null || foundItem === void 0 ? void 0 : foundItem.target)) { return []; } return [genNewImport(foundItem === null || foundItem === void 0 ? void 0 : foundItem.target, [])]; } var parsedImportList = originImportedList.map(function (curOrigin) { var current = parsedConfigList.find(function (item) { var source = item.source, sourceType = item.sourceType, sourceName = item.sourceName; if (originSource !== source || curOrigin.type !== sourceType) { return false; } if (sourceType === IImportType.ImportSpecifier) { return curOrigin.imported === sourceName; } // ImportDefaultSpecifier 和 ImportNamespaceSpecifier 直接返回 true return true; }); if (!current) { return __assign(__assign({}, curOrigin), { _type: 'OLD', target: originSource, targetName: curOrigin.imported, targetType: curOrigin.type }); } return __assign(__assign(__assign({}, current), curOrigin), { _type: 'NEW' }); }); var newImportList = parsedImportList.filter(function (item) { return item._type === 'NEW'; }); var oldImportList = parsedImportList.filter(function (item) { return item._type === 'OLD'; }); var obj = localFlatten(newImportList); var oldObj = localFlatten(oldImportList); // newImportList.reduce((acc: Record<string, Array<{ // type: IImportType; // local: string; // imported: string; // source: string; // target: string; // sourceName: string; // sourceType: IImportType; // targetName: string; // targetType: IImportType; // }>>, current) => { // const { target } = current!; // if (acc[target]) { // acc[target].push(current!); // } else { // acc[target] = [current!]; // } // return acc; // }, {}); var nodeList = Object.keys(obj).map(function (source) { var node = genNewImport(source, obj[source]); return node; }); var oldNodeList = Object.keys(oldObj).map(function (source) { var node = genNewImport(source, oldObj[source]); return node; }); if (nodeList.length) { return __spreadArray(__spreadArray([], nodeList, true), [oldNodeList], false); } return []; } function genNewImport(source, importedList) { var t = require('@babel/types'); var list = importedList.map(function (current) { var local = current.local, targetType = current.targetType, targetName = current.targetName; if (targetType === IImportType.ImportSpecifier) { return t.ImportSpecifier(t.identifier(local), t.identifier(targetName)); } if (targetType === IImportType.ImportDefaultSpecifier) { return t.ImportDefaultSpecifier(t.identifier(local)); } if (targetType === IImportType.importNamespaceSpecifier) { return t.ImportNamespaceSpecifier(t.identifier(local)); } }); return t.ImportDeclaration(list, t.StringLiteral(source)); } var B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var B64RE = /^(?:[A-Za-z\d+/]{4})*?(?:[A-Za-z\d+/]{2}(?:==)?|[A-Za-z\d+/]{3}=?)?$/; var _fromCC = String.fromCharCode.bind(String); /* eslint-disable */ var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; var utob = function utob(u) { return u.replace(re_utob, cb_utob); }; var cb_utob = function cb_utob(c) { if (c.length < 2) { var cc = c.charCodeAt(0); return cc < 0x80 ? c : cc < 0x800 ? _fromCC(0xc0 | cc >>> 6) + _fromCC(0x80 | cc & 0x3f) : _fromCC(0xe0 | cc >>> 12 & 0x0f) + _fromCC(0x80 | cc >>> 6 & 0x3f) + _fromCC(0x80 | cc & 0x3f); } var cc = 0x10000 + (c.charCodeAt(0) - 0xD800) * 0x400 + (c.charCodeAt(1) - 0xDC00); return _fromCC(0xf0 | cc >>> 18 & 0x07) + _fromCC(0x80 | cc >>> 12 & 0x3f) + _fromCC(0x80 | cc >>> 6 & 0x3f) + _fromCC(0x80 | cc & 0x3f); }; var encode = function encode(str) { return innerEncode(utob(str)); }; // 小程序版本的btoa var innerEncode = function innerEncode(string) { string = String(string); var bitmap; var a; var b; var c; var result = ''; var i = 0; var rest = string.length % 3; for (; i < string.length;) { if ((a = string.charCodeAt(i++)) > 255 || (b = string.charCodeAt(i++)) > 255 || (c = string.charCodeAt(i++)) > 255) throw new TypeError('Failed to execute \'btoa\' on \'Window\': The string to be encoded contains characters outside of the Latin1 range.'); bitmap = a << 16 | b << 8 | c; result += B64.charAt(bitmap >> 18 & 63) + B64.charAt(bitmap >> 12 & 63) + B64.charAt(bitmap >> 6 & 63) + B64.charAt(bitmap & 63); } return rest ? result.slice(0, rest - 3) + '==='.substring(rest) : result; }; /* eslint-disable */ var re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g; var _tidyB64 = function _tidyB64(s) { return s.replace(/[^A-Za-z0-9\+\/]/g, ''); }; var cb_btou = function cb_btou(cccc) { switch (cccc.length) { case 4: var cp = (0x07 & cccc.charCodeAt(0)) << 18 | (0x3f & cccc.charCodeAt(1)) << 12 | (0x3f & cccc.charCodeAt(2)) << 6 | 0x3f & cccc.charCodeAt(3); var offset = cp - 0x10000; return _fromCC((offset >>> 10) + 0xD800) + _fromCC((offset & 0x3FF) + 0xDC00); case 3: return _fromCC((0x0f & cccc.charCodeAt(0)) << 12 | (0x3f & cccc.charCodeAt(1)) << 6 | 0x3f & cccc.charCodeAt(2)); default: return _fromCC((0x1f & cccc.charCodeAt(0)) << 6 | 0x3f & cccc.charCodeAt(1)); } }; var btou = function btou(b) { return b.replace(re_btou, cb_btou); }; var _unURI = function _unURI(a) { return _tidyB64(a.replace(/[-_]/g, function (m0) { return m0 == '-' ? '+' : '/'; })); }; var decode = function decode(str) { return btou(innerDecode(_unURI(str))); }; // 小程序版本的atob var innerDecode = function innerDecode(string) { string = String(string).replace(/[\t\n\f\r ]+/g, ''); if (!B64RE.test(string)) throw new TypeError('Failed to execute \'atob\' on \'Window\': The string to be decoded is not correctly encoded.'); string += '=='.slice(2 - (string.length & 3)); var bitmap; var result = ''; var r1; var r2; var i = 0; for (; i < string.length;) { bitmap = B64.indexOf(string.charAt(i++)) << 18 | B64.indexOf(string.charAt(i++)) << 12 | (r1 = B64.indexOf(string.charAt(i++))) << 6 | (r2 = B64.indexOf(string.charAt(i++))); result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255) : r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255) : String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255); } return result; }; /** * 表单等数据变更时,提示用户是否确认离开当前页面 * @param checkDataCallback 可选,用于检查是否有未保存的数据变更,返回 true 则提示用户,返回 false 则不提示 * @returns 一个数组,第一个元素是移除事件监听的函数,第二个元素是事件处理函数 * * @example * ```ts * const [removeBeforeUnload] = initBeforeUnload(() => { * return form.isDirty; // 假设 form.isDirty 表示表单是否有未保存的更改 * }); * * // 在组件卸载或不再需要提示时调用 * removeBeforeUnload(); * ``` */ function initBeforeUnload(checkDataCallback) { var handler = function handler(event) { if (typeof checkDataCallback === 'function' && !checkDataCallback()) { return; } // Some browsers may not display the prompt if a custom message is set. // event.returnValue = 'You have unsaved changes. Are you sure you want to leave?'; // Cancel the event as stated by the standard. event.preventDefault(); // Chrome requires returnValue to be set. event.returnValue = ''; }; window.addEventListener('beforeunload', handler); return [function () { window.removeEventListener('beforeunload', handler); }, handler]; } /** * 格式化 bite 单位,最多保留2位小数,最大单位为BB * @param number size bite 单位 * @returns 格式化的字符 * @example * * formatBite(1) * // 1B * * formatBite(100) * // 100B * * formatBite(1000) * // 1000B * * formatBite(10000) * // 9.77KB * * formatBite(100000) * // 97.66KB * * formatBite(1000000) * // 976.56KB * * formatBite(10000000) * // 9.54MB */ function formatBite(size) { var UNIT = 1024; var UNIT_LIST = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'BB']; var res = size; var loopTime = 0; while (res > UNIT && loopTime < UNIT_LIST.length - 1) { res = res / UNIT; loopTime += 1; } return parseFloat(res.toFixed(2)) + UNIT_LIST[loopTime]; } /** * 写入文件 * @param {string} file 文件地址 * @param {any} data 文件数据 * @param {boolean} [isJson] 是否需要 json 序列化 * @example * ```ts * writeFileSync('a', 'b.txt', false); * * writeFileSync({ a: 1 }, 'b.json', true); * ``` */ function writeFileSync(file, data, isJson) { if (isJson === void 0) { isJson = false; } var fileData = isJson ? JSON.stringify(data, null, 2) : data; fs.writeFileSync(file, fileData, { encoding: 'utf-8' }); } /** * 读取文件 * @param {string} file 文件地址 * @param {boolean} [isJson] 是否需要 json 反序列化 * @returns {any} 文件内容 * @example * ```ts * readFileSync('b.txt', false); * * readFileSync('b.json', true); * ``` */ function readFileSync(file, isJson) { if (isJson === void 0) { isJson = false; } var content = fs.readFileSync(file, { encoding: 'utf-8' }); var result = content; if (isJson) { try { result = JSON.parse(content); } catch (e) {} } return result; } function isDirectory(filePath) { if (filePath === void 0) { filePath = ''; } var stat = fs.lstatSync(filePath); return stat.isDirectory(); } /* eslint-disable @typescript-eslint/no-require-imports */ /** * nodejs 中调用 child_process.execSync 执行命令, * 这个方法会对输出结果截断,只返回第一行内容 * @param {string} command 命令 * @param {string} root 执行命令的目录 * @param {string | object} stdio 结果输出,默认为 pipe * @returns {string} 命令执行结果 */ function execCommand(command, root, options) { var _a, _b, _c; if (!root) { root = process.cwd(); } var execSync = require('child_process').execSync; var innerOptions = {}; if (typeof options === 'string') { innerOptions = { stdio: options }; } else if (_typeof(options) === 'object') { innerOptions = options; } var stdio = (_a = innerOptions === null || innerOptions === void 0 ? void 0 : innerOptions.stdio) !== null && _a !== void 0 ? _a : 'pipe'; var line = (_b = innerOptions === null || innerOptions === void 0 ? void 0 : innerOptions.line) !== null && _b !== void 0 ? _b : 0; var res = execSync(command, { cwd: root || process.cwd(), encoding: 'utf-8', stdio: stdio || 'pipe' }); if (line > -1) { return ((_c = res === null || res === void 0 ? void 0 : res.split('\n')[line]) === null || _c === void 0 ? void 0 : _c.trim()) || ''; } return res; } function getKeyValue(key, sourceLine) { var result; var ma; var re = new RegExp("".concat(key, "\\s*=\\s*(.*?)(\\s|$)")); for (var _i = 0, sourceLine_1 = sourceLine; _i < sourceLine_1.length; _i++) { var line = sourceLine_1[_i]; if (line.startsWith('#')) { // 忽略注释行 continue; } ma = line.match(re); if (ma) { result = ma[1] || ''; break; } } return result; } function getEnvVariableMap(filepath) { var sourceStr = ''; var re = new RegExp('(.*?)\\s*=\\s*(.*?)(\\s|$)'); if (fs.existsSync(filepath)) { sourceStr = fs.readFileSync(filepath, 'utf-8'); } else { sourceStr = filepath; } var sourceLine = sourceStr.split('\n'); var result = {}; for (var _i = 0, sourceLine_2 = sourceLine; _i < sourceLine_2.length; _i++) { var line = sourceLine_2[_i]; if (line.startsWith('#')) { // 忽略注释行 continue; } var match = line.match(re); if (match === null || match === void 0 ? void 0 : match[1]) { result[match[1]] = match[2] || ''; } } return result; } /** * 读取文件中环境变量的值,支持: * - NPM_TOKEN=xxx * - NPM_TOKEN = xxx * @param {string} key 环境变量的key * @param {string} filepath 保存环境变量的文件路径 * @returns {string} 环境变量的值 */ function readEnvVariable(key, filepath) { if (!fs.existsSync(filepath)) { console.log('[readEnvVariable] 文件不存在:', filepath, ',请先创建文件'); return ''; } try { var sourceStr = fs.readFileSync(filepath, 'utf-8'); var sourceLine = sourceStr.split('\n'); return getKeyValue(key, sourceLine); } catch (e) { console.log('[readEnvVariable] 打开文件失败:', filepath); process.exit(1); } } function getPublishRootDir() { var rootDir = process.cwd(); return rootDir; } function findPublishSh(dir) { var FILE_NAME = 'publish.sh'; var file = path.resolve(dir, FILE_NAME); if (fs.existsSync(file)) { return file; } } function getPublishBashPath() { return findPublishSh(path.resolve(__dirname, '..')) || findPublishSh(path.resolve(__dirname, '../bin')) || findPublishSh(path.resolve(__dirname, '../../bin')) || 'ERROR_FILE'; } function getPublishEnvValue(key) { var rootDir = getPublishRootDir(); var localEnvPath = path.join(rootDir, '.env.local'); var envPath = path.join(rootDir, '.env'); var envValue = readEnvVariable(key, envPath); var localEnvValue = readEnvVariable(key, localEnvPath); return localEnvValue || envValue || ''; } function getPublishModuleName(dir) { if (dir === void 0) { dir = ''; } return dir.split('/')[1] || ''; } var DEFAULT_HOST_TARGET_DIR = '/root/ft_local'; function build(_a) { var files = _a.files, bundleName = _a.bundleName; return new Promise(function (resolve, reject) { console.log('[build] 开始打包...'); console.log('[build] Files: ', files); // 创建dist目录 var fse = require('fs-extra'); fse.ensureDirSync('./dist'); var tar = require('tar'); // 打包 tar.c({ gzip: true, file: "dist/".concat(bundleName, ".tar.gz"), filter: function filter() { return true; } }, __spreadArray([], files, true)).then(function () { console.log('[build] 打包完成'); resolve(true); })["catch"](function (err) { console.log('[build] 打包失败'); reject(err); }); }); } function upload(_a) { var root = _a.root, bundleName = _a.bundleName, hostName = _a.hostName, hostPwd = _a.hostPwd, _b = _a.hostTargetDir, hostTargetDir = _b === void 0 ? DEFAULT_HOST_TARGET_DIR : _b; if (!hostName || !hostName || !bundleName) { throw new Error('参数不全'); } console.log('[upload] 开始上传...'); var publishBash = getPublishBashPath(); execCommand("sh ".concat(publishBash, " ./dist/").concat(bundleName, ".tar.gz ").concat(hostTargetDir, " ").concat(hostName, " ").concat(hostPwd), root, 'inherit'); console.log('[upload] 上传完成'); } /** * 打包并上传到服务器 * @param {object} options 配置 * @param {string} options.hostName 服务器名称 * @param {string} options.hostPwd 服务器密码 * @param {string} [options.root] 项目根目录 * @param {string} [options.bundleName] 打包文件名称 * @example * * await buildAndUpload({ * hostName: '9.9.9.9', * hostPwd: 'xxxx', * bundleName: 'cron-job-svr', * }); * */ function buildAndUpload(_a) { var _b = _a.root, root = _b === void 0 ? process.cwd() : _b, _c = _a.bundleName, bundleName = _c === void 0 ? 'bundle' : _c, hostName = _a.hostName, hostPwd = _a.hostPwd, hostTargetDir = _a.hostTargetDir; return __awaiter(this, void 0, void 0, function () { var path, pkgPath, fs, _d, files, flag; return __generator(this, function (_e) { switch (_e.label) { case 0: if (!root) { root = process.cwd(); } path = require('path'); pkgPath = path.resolve(root, 'package.json'); fs = require('fs'); if (!fs.existsSync(root)) { throw new Error('ERROR: root 不存在'); } if (!fs.existsSync(pkgPath)) { throw new Error('ERROR: package.json 不存在'); } _d = readFileSync(pkgPath, true).files, files = _d === void 0 ? [] : _d; if (files.indexOf('.env.local') < 0 && fs.existsSync('.env.local')) { files.push('.env.local'); } return [4 /*yield*/, build({ files: files, bundleName: bundleName })]; case 1: flag = _e.sent(); if (!flag) return [2 /*return*/]; return [4 /*yield*/, upload({ root: root, bundleName: bundleName, hostName: hostName, hostPwd: hostPwd, hostTargetDir: hostTargetDir })]; case 2: _e.sent(); return [2 /*return*/, files]; } }); }); } /** * 匹配正则,获取匹配到的列表 * @param {string} content 输入内容 * @param {RegExp} reg 正则 * @returns 匹配列表 * * @example * ```ts * getMatchListFromReg(content, /emit\('([^',]+)'/g); * * // ['start', 'end'] * ``` */ function getMatchListFromReg(content, reg) { var match = reg.exec(content); var result = []; while (match === null || match === void 0 ? void 0 : match[1]) { result.push(match[1]); match = reg.exec(content); } return result; } var PRE_RELEASE_VERSION = /\d+\.\d+\.\d+-(\w+).\d+/; /** * 获取预发布版本标签,比如 alpha, beta * @param {string} version 版本号 * @returns 标签 * @example * ```ts * getPreReleaseTag('1.2.2-beta.0') * // beta * ``` */ function getPreReleaseTag(version) { var match = version.match(PRE_RELEASE_VERSION); if (!(match === null || match === void 0 ? void 0 : match[1])) { return ''; } return match[1]; } function getHtmlContent(buildPath) { var htmlPath = path.resolve(buildPath, 'index.html'); var content = fs.readFileSync(htmlPath, { encoding: 'utf-8' }); return content; } /** * * result示例: * * [ * 'static/js/chunk-vendors.59912eed.js', * 'static/js/index.8ec239e5.js', * 'static/index.b0707a6a.css' * ] * * @ignore */ function getEntryFiles(content, domain) { var scriptReg = new RegExp("<script .*?src=\"".concat(domain, "/?(.+?)\".*?/?>"), 'g'); var cssReg = new RegExp("<link .*?href=\"".concat(domain, "/?(.+?)\".*?/?>"), 'g'); var result = __spreadArray(__spreadArray([], getMatchListFromReg(content, scriptReg), true), getMatchListFromReg(content, cssReg), true); console.log('[getEntryFiles] result', result); return result; } function getBundleSize(list, buildPath) { return list.map(function (item) { var filePath = path.resolve(buildPath, item); console.log('[getBundleSize] filePath', filePath); var isExist = fs.existsSync(filePath); if (isExist) { var stat = fs.statSync(filePath); return { file: item, size: stat.size, time: new Date(stat.ctime).getTime() }; } }).filter(function (item) { return item; }); } /** * 分析首页Bundle信息 * * @export * @param config 配置 * @param {string} config.domain 域名 * @param {string} config.buildPath 打包路径 * @returns {*} * * @example * ```ts * analyzeIndexBundle({ * domain: '', * buildPath: '', * }) * ``` */ function analyzeIndexBundle(_a) { var domain = _a.domain, buildPath = _a.buildPath; var content = getHtmlContent(buildPath); var fileList = getEntryFiles(content, domain); var bundleSizeList = getBundleSize(fileList, buildPath); return bundleSizeList; } function getCanvas() { try { // eslint-disable-next-line @typescript-eslint/no-require-imports var canvasLibrary = require('canvas'); return canvasLibrary; } catch (err) {} } /** * 为图片增加文字 * * @param {Object} config 配置 * @param {number} config.width 宽度 * @param {number} config.height 高度 * @param {Array<string>} config.textList 文字列表,支持多行 * @param {string} config.imgPath 图片路径 * @returns {string} canvas.toDataURL生成的base64图片 * * @example * * ```ts * const imgUrl = addTextForImg({ * width: 300, * height: 300, * textList: ['第一行', '第二行'], * imgPath: './test.png', * }) * ``` */ function addTextForImg(_a) { var width = _a.width, height = _a.height, textList = _a.textList, imgPath = _a.imgPath; return __awaiter(this, void 0, void 0, function () { function drawBackground() { ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, canvas.width, canvas.height); } function fillTitle(textList) { ctx.lineWidth = 1; ctx.strokeStyle = '#ccc'; ctx.textAlign = 'start'; ctx.font = '10px Arial'; ctx.fillStyle = '#000'; for (var j = 0; j < textList.length; j++) { ctx.fillText(textList[j], 15, 20 + j * lineHeight); } } var canvasLibrary, sizeOf, createCanvas, loadImage, image, lineHeight, dpr, topHeight, dimensions, oHeight, oWidth, canvas, ctx, imgUrl; return __generator(this, function (_b) { switch (_b.label) { case 0: canvasLibrary = getCanvas(); if (!canvasLibrary) return [2 /*return*/, '']; sizeOf = require('image-size'); createCanvas = canvasLibrary.createCanvas, loadImage = canvasLibrary.loadImage; return [4 /*yield*/, loadImage(imgPath)]; case 1: image = _b.sent(); lineHeight = 15; dpr = 2; topHeight = textList.length * lineHeight + 15; dimensions = sizeOf(imgPath); oHeight = dimensions.height, oWidth = dimensions.width; if (!width) { width = oWidth; } if (!height) { height = oHeight; } canvas = createCanvas(width * dpr, (height + topHeight) * dpr); ctx = canvas.getContext('2d'); ctx.scale(dpr, dpr); drawBackground(); ctx.drawImage(image, 0, topHeight, width, width); fillTitle(textList); imgUrl = canvas.toDataURL(); return [2 /*return*/, imgUrl]; } }); }); } /** * 递归拉平数组 * @param list 数组 * @returns 数组 * * @example * * flat([[[1, 2, 3], 4], 5]) * * // [1, 2, 3, 4, 5] */ function flat(list) { return list.reduce(function (acc, item) { return acc.concat(Array.isArray(item) ? flat(item) : item); }, []); } /** * 拉平数组,不会递归处理 * @param {Array<Object>} list - 对象数组 * @param {string} key - 对象的key * @returns {object} 拉平后的对象 * * @example * * const list = [{id: 1, name: 'a'}, {id: 2, name: 'b'}] * * flatten(list, 'id') * * // {1: {id: 1, name: 'a'}, 2: {id: 2, name: 'b'}} * */ function flatten(list, key) { return list.reduce(function (acc, item) { acc[item[key]] = item; return acc; }, {}); } /** * 打乱数组顺序 * * @param {Array<any>} array - 数组 * @returns {Array<any>} 乱序后的数组 * * @example * * shuffle([1, 2, 3, 4, 5]) * * // [3, 2, 1, 4, 5] * */ function shuffle(array) { var _a; var arr = __spreadArray([], array, true); var m = arr.length; while (m > 1) { var index = Math.floor(Math.random() * m); m -= 1; _a = [arr[index], arr[m]], arr[m] = _a[0], arr[index] = _a[1]; } return arr; } /** * 获取累积宽度 * @param {Array<number>} cellWidthList - 宽度列表 * @param {number} idx - 当前idx * @returns {number} 累计宽度 * * @example * * getAccCellWidth([20, 10, 20, 10], 1) * * // 30 */ function getAccCellWidth(cellWidthList, idx) { var res = 0; for (var i = 0; i <= Math.min(idx, cellWidthList.length - 1); i++) { res += cellWidthList[i]; } return res; } /** * 获取相对于过去数据的比例 * @param {number} value 当前数据 * @param {number} preValue 之前数据 * @returns {string} 比例 * * @example * * getUnitPreviousRatio(1, 0) * // +999+% */ function getUnitPreviousRatio(value, preValue) { var interval = value - preValue; var symbol = interval > 0 ? '+' : ''; if (preValue === 0) { preValue = 0.01; } var intervalRatio = (interval / preValue * 100).toFixed(1); if (+intervalRatio > 999) { intervalRatio = '999+'; } return "".concat(symbol).concat(intervalRatio, "%"); } /** * 获取占比 * @param {number} summary 总数据 * @param {number} part 部分数据 * @returns {number} 比例 * @example * getRatio(0, 1) * // 0 * * getRatio(1, 0) * // 0 * * getRatio(1, 1) * // 100 * * getRatio(1, .5) * // 50 */ function getPartRatio(summary, part) { if (!summary) return 0; if (!part) return 0; return +(part / summary * 100).toFixed(2); } /** * * 阿拉伯数字和中文数字映射表,0 - 32 * @type {object} * @example * * console.log(NUMBER_CHI_MAP[1]); * // '一' * * console.log(NUMBER_CHI_MAP[2]); * // '二' */ var NUMBER_CHI_MAP = { 0: '零', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '七', 8: '八', 9: '九', 10: '十', 11: '十一', 12: '十二', 13: '十三', 14: '十四', 15: '十五', 16: '十六', 17: '十七', 18: '十八', 19: '十九', 20: '二十', 21: '二十一', 22: '二十二', 23: '二十三', 24: '二十四', 25: '二十五', 26: '二十六', 27: '二十七', 28: '二十八', 29: '二十九', 30: '三十', 31: '三十一', 32: '三十二' }; /** * 获取千分位分隔符 * @param {string | number} value 输入数字 * @returns {string} 处理后的数字 * * @example * * getThousandSeparator('123123123') * * // => 123,123,123 * * getThousandSeparator('12312312') * * // => 12,312,312 */ function getThousandSeparator(value) { var str = "".concat(value); // 分割整数和小数部分 var parts = str.split('.'); // 只对整数部分添加千分位分隔符 parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); // 重新组合整数和小数部分 return parts.join('.'); } /** * 获取千分位分隔符,处理数字之间有空格的情况 * @param {string | number} value 输入数字 * @returns {string} 处理后的数字 * * @example * getThousandSeparator2('12345678 123456789') * * // => 12,345,678 123,456,789 * */ function getThousandSeparator2(value) { var reg = /\B(?=(\d{3})+\b)/g; return "".concat(value).replace(reg, ','); } /** * 在区间内获取随机整数 * @param {number} min 最小值 * @param {number} max 最大值 * @returns 随机数 * * @example * ```ts * random(0, 19) // 1 * ``` */ function random(min, max) { if (min >= 0 && max > 0 && max >= min) { var gap = max - min + 1; return Math.floor(Math.random() * gap + min); } return 0; } function getRandomNumber(min, max) { var result = Math.random() * (max - min) + min; return result; } /** * 数字左侧加 0,直到满足长度要求 * @param {string | number} num 当前数字 * @param {number} [targetLength=2] 目标长度 * @returns {string} 新的字符串 * @example * ```ts * padZero(1, 3); // 001 * ``` */ function padZero(num, targetLength) { if (targetLength === void 0) { targetLength = 2; } var str = "".concat(num); while (str.length < targetLength) { str = "0".concat(str); } return str; } /** * add num and avoid float number * @param {number} num1 第1个数字 * @param {number} num2 第2个数字 * @returns {number} 结果 * @example * ```ts * addNumber(0.1, 0.2); // 0.3 * ``` */ function addNumber(num1, num2) { var cardinal = Math.pow(10, 10); return Math.round((num1 + num2) * cardinal) / cardinal; } /** * 根据边界值修正数字 * @param {number} num 待处理的数字 * @param {number} min 边界最小值 * @param {number} max 边界最大值 * @returns {number} 处理结果 * @example * ```ts * range(12, 1, 2); // 2 * ``` */ function range(num, min, max) { return Math.min(Math.max(num, min), max); } /** * 判断数组是否全部相等 * @param {Array<number | string>} list - 数组 * @returns {Boolean} 是否全部相等 * * @example * isListAllEqual([0, 0, 0]) * * // true * * isListAllEqual([0, 0, 2]) * * // false */ function isListAllEqual(list) { if (list === void 0) { list = []; } if (!list.length) return true; var value = list[0]; for (var _i = 0, _a = list.slice(1); _i < _a.length; _i++) { var item = _a[_i]; if (item !== value) return false; } return true; } /** * 获取对象的value列表,并输出大对象形式 * @param {Array<any>} data * @returns {Object} 处理后的对象 * * @example * * const data = [ * { * Project: 'x', * Request: 1, * Score: 'a' * }, * { * Project: 'y', * Request: 2, * Score: 'b' * }] * * getKeyValuesMap(data) * * // 结果为: * { * Project: ['x', 'y'], * Request: [1, 2], * Score: ['a', 'b'], * } * * // 也支持参数为带value属性的对象数组,如: * * const data = [ * { * Project: { * value: 'x' * } * },{ * Project: { * value: 'y' * } * }] * * // 结果为: * { * Project: ['x', 'y'] * } */ function getKeyValuesMap(data) { if (data === void 0) { data = []; } if (!data.length) return {}; var keys = Object.keys(data[0]); var keyValueMap = {}; data.forEach(function (item) { keys.forEach(function (key) { var _a; // 如果有value,就取value,否则直接取item[key] var value = ((_a = item[key]) === null || _a === void 0 ? void 0 : _a.value) || item[key]; if (keyValueMap[key]) { keyValueMap[key].push(value); } else { keyValueMap[key] = [value]; } }); }); return keyValueMap; } /** * 标记最大最小值 * @private * @param {object} params 参数对象 * @param {Array<number>} params.values 待处理的数组 * @param {number} params.value 当前值 * @param {Object} params.obj 迭代中的对象 * @returns {Object} 处理后的对象 */ function markMaxAndMinOfObj(_a) { var values = _a.values, value = _a.value, obj = _a.obj; var idx = values.indexOf(value); var lastIdx = values.indexOf(value); var newObj = __assign(__assign({}, obj), { idx: idx, lastIdx: lastIdx }); if (!isListAllEqual(values)) { var len = values.length; var isMax = idx === 0; var isSecondMax = idx === 1; var isMin = idx === len - 1; var isSecondMin = idx === len - 2; newObj = __assign(__assign({}, newObj), { isMax: isMax, isMin: isMin, isSecondMax: isSecondMax, isSecondMin: isSecondMin }); } return newObj; } /** * 获取相对上次的比例,会给输入的对象数组的每一项增加 ratio、previousValue 属性 * @param {Array<Object>} data - 输入数据 * @param {Object} preDataMap - 上次数据的map * @param {string} uniqKey - 唯一键 * * @example * const data = [{ * Project: { value: 'mj-match', name: 'Project' }, * Request: { * value: 854, * name: 'Request', * idx: 19, * lastIdx: 19, * isMax: false, * isMin: false, * isSecondMax: false, * isSecondMin: true, * }, * }]; * * const preDataMap = { * 'mj-match': { * Project: 'mj-match', * Request: 4, * Score: 91.81, * FirstLoadTime: 178, * WholePageTime: 1035, * ParseDomTime: 484, * DNSLinkTime: 0, * DOMTime: 414, * TCP: 0, * HTTP: 275, * BackEnd: 60, * CGIFailNum: 0, * ErrorLogNum: 0, * CGIRequestNum: 83, * }, * }; * * getPreviousRatio(data, preDataMap); * * // data会变成: * [{ * Project: { value: 'mj-match', name: 'Project' }, * Request: { * value: 854, * name: 'Request', * idx: 19, * lastIdx: 19, * isMax: false, * isMin: false, * isSecondMax: false, * isSecondMin: true, * * previousValue: 4, // 新增属性 * ratio: "+999+%" // 新增属性 * }, * }]; */ function getPreviousRatio(data, preDataMap, uniqKey) { if (data === void 0) { data = []; } if (preDataMap === void 0) { preDataMap = {}; } if (uniqKey === void 0) { uniqKey = 'Project'; } data.forEach(function (item) { Object.keys(item).forEach(function (key) { var _a, _b; var obj = item[key]; if (typeof (obj === null || obj === void 0 ? void 0 : obj.value) === 'number') { var uniqVal = (_a = item[uniqKey]) === null || _a === void 0 ? void 0 : _a.value; var preValue = (_b = preDataMap === null || preDataMap === void 0 ? void 0 : preDataMap[uniqVal]) === null || _b === void 0 ? void 0 : _b[key]; if (preValue === undefined) { obj.ratio = ''; } else { obj.ratio = getUnitPreviousRatio(obj.value, preValue); obj.previousValue = preValue; } } }); }); } /** * 给对象数组的每一项,添加isMax、isMin、、isSecondMax、isSecondMin、idx、lastIdx等属性 * @param {Array<object>} data 原始数据 * @param {Array<string>} reverseScoreKeys - 逆序的key列表 * @returns {Object} 处理后的数据 * * @example * const data = [{ * ProjectName: { name: 'ProjectName', value: '麻将赛事' }, * PagePv: { name: 'PagePv', value: 2877 }, * }, { * ProjectName: { name: 'ProjectName', value: '斗地主赛事' }, * PagePv: { name: 'PagePv', value: 7 }, * }, * // ... * ]; * * getMaxAndMinIdx(data, []) * * // => * [{ * ProjectName: { name: 'ProjectName', value: '麻将赛事' }, * PagePv: { * name: 'PagePv', * value: 2877, * idx: 6, * lastIdx: 6, * isMax: false, * isMin: false, * isSecondMax: false, * isSecondMin: false, * }, * }]; * */ function getMaxAndMinIdx(data, reverseScoreKeys) { if (data === void 0) { data = []; } if (reverseScoreKeys === void 0) { reverseScoreKeys = []; } if (!data.length) return []; var keys = Object.keys(data[0]); var keyValueMap = getKeyValuesMap(data); var parsedData = data.map(function (item) { var temp = __assign({}, item); keys.forEach(function (key) { var values = keyValueMap[key]; var itemInfo = item[key] || {}; if (values && typeof itemInfo.value === 'number') { if (reverseScoreKeys.indexOf(key) > -1) { values.sort(function (a, b) { if (a > b) return 1; if (a < b) return -1; return 0; }); } else { values.sort(function (a, b) { if (a > b) return -1; if (a < b) return 1; return 0; }); } temp[key] = markMaxAndMinOfObj({ values: values, value: itemInfo.value, obj: temp[key] }); } }); return temp; }); return parsedData; } /** * 拉平之前数据 * @param {Array<Object>} preDataList 之前的数据,作为对照 * @param {string} key 主键 * @returns {Object} preDataMap * * @example * const data = [{ * ProjectName: { name: 'ProjectName', value: '研发平台' }, * PagePv: { name: 'PagePv', value: 152 }, * PageUv: { name: 'PageUv', value: 7 }, * Score: { name: 'Score', value: 93.92 }, * PageDuration: { name: 'PageDuration', value: 1281.58 }, * PageError: { name: 'PageError', value: 2 }, * }]; * * flattenPreData(data, 'ProjectName'); * * // 输出 * { * 研发平台: { * ProjectName: '研发平台', * PagePv: 152, * PageUv: 7, * Score: 93.92, * PageDuration: 1281.58, * PageError: 2, * }, * }; */ function flattenPreData(preDataList, key) { var preDataMap = preDataList.reduce(function (acc, item) { var _a; acc[((_a = item[key]) === null || _a === void 0 ? void 0 : _a.value) || 'DEFAULT_KEY'] = Object.values(item).reduce(function (ac, it) { ac[it.name] = it.value; return ac; }, {}); return acc; }, {}); return preDataMap; } /** * 对比两个对象列表 * @param {Array<object>} list 现在数据 * @param {Array<object>} preList 参照数据 * @param {string} key 唯一key名称 * @returns {Array<object>} 对比结果,增加为list的每一项增加previousValue和ratio属性 * @example * const list = [ * { * ProjectName: { name: 'ProjectName', value: '脚手架' }, * PagePv: { name: 'PagePv', value: 544343 }, * PageUv: { name: 'PageUv', value: 225275 }, * } * ] * * const preList = [ * { * ProjectName: { name: 'ProjectName', value: '脚手架' }, * PagePv: { name: 'PagePv', value: 123123 }, * PageUv: { name: 'PageUv', value: 33333 }, * } * ] * * compareTwoList(list, preList, 'ProjectName') * * console.log(list) * * [ * { * ProjectName: { name: 'ProjectName', value: '脚手架' }, * PagePv: { * name: 'PagePv', * value: 544343, * ratio: '+342.1%', * previousValue: 123123 * }, * PageUv: { * name: 'PageUv', * value: 225275, * ratio: '+575.8%', * previousValue: 33333 * } * } * ] */ function compareTwoList(list, preList, key) { var preDataMap = flattenPreData(preList, key); getPreviousRatio(list, preDataMap, key); return list; } function sortByStr(list, key, reverse) { if (reverse === void 0) { reverse = false; } list.sort(function (a, b) { var valueA = key ? a[key] : a; var valueB = key ? b[key] : b; if (reverse) { return valueB.localeCompare(valueA); } return valueA.localeCompare(valueB); }); } function getStrListLength(list) { return list.reduce(function (acc, item) { return acc + item.length; }, 0); } function splitLongList(list, threshold, max) { if (threshold === void 0) { threshold = 3800; } if (max === void 0) { max = 3; } var strLen = getStrListLength(list); if (strLen <= threshold) { return [list]; } var result = []; var temp = []; for (var i = 0; i < list.length; i++) { var item = list[i]; temp.push(item); var tempLen = getStrListLength(temp); if (tempLen >= threshold) { result.push(temp); temp = []; if (result.length >= max - 1) { temp = list.slice(i + 1); break; } } } result.push(temp); return result; } /* eslint-disable @typescript-eslint/no-require-imports */ var cellHeight = 20; var extraHeight = 15; var extraBottom = 10; var extraWidth = 3; var maxColor = '#fc5531'; var minColor = 'green'; function parseCellValue(val) { if (val === undefined || val === null) return ''; return "".concat(val); } /** * 判断是否有比例,只要一行有比例,即为有 * @ignore */ function judgeRatio(data, value) { if (!value) return false; return !!(data || []).find(function (item) { var values = Object.values(item) || []; return values.find(function (value) { return !!value.ratio; }); }) && !isNaN(value); } /** * 创建canvas的table * @param {object} config 输入配置 * @param {Array<object>} config.data 输入数据 * @param {Array<string>} config.headers 表头列表 * @param {Array<number>} config.cellWidthList 每一格的宽度列表 * @param {string} config.title 标题 * @returns {string} 图片url * @example * * const tableData = [ * { * ProjectName: { name: 'ProjectName', value: 'ProjectA' }, * ALL_SUMMARY: { * name: 'ALL_SUMMARY', * value: 4987, * ratio: '+26.2%', * previousValue: 3953, * idx: 0, * lastIdx: 0, * isMax: true, * isMin: false, * isSecondMax: false, * isSecondMin: false, * }, * ALL_FAIL: { * // ... * }, * }, * { * ProjectName: { name: 'ProjectName', value: 'ProjectB' }, * // ... * }, * ]; * * createCanvasTable({ * data: tableData, * headers: getHeaders(tableData), * title: `007日报 ${date}`, * cellWidthList: [ * 95, * 65, * 65, * 65, * ], * }); */ function createCanvasTable(_a) { var data = _a.data, headers = _a.headers, cellWidthList = _a.cellWidthList, title = _a.title; var canvasLibrary = getCanvas(); if (!canvasLibrary) return ''; var createCanvas = canvasLibrary.createCanvas; var getAccCellWidth$1 = getAccCellWidth.bind(null, cellWidthList); var width = getAccCellWidth$1(headers.length - 1) * 2 + extraWidth * 4; var height = (data.length + 1) * cellHeight * 2 + extraHeight * 2 + extraBottom; var canvas = createCanvas(width, height); var ctx = canvas.getContext('2d'); function fillBackground() { ctx.font = '7px Arial'; ctx.scale(2, 2); ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, canvas.width, canvas.height); } function fillTitle() { ctx.lineWidth = 1; ctx.strokeStyle = '#ccc'; ctx.textAlign = 'start'; ctx.font = '9px Arial'; ctx.fillStyle = '#000'; ctx.fillText(parseCellValue(title), 5, 10); } // 表头绘制 function fillTableHeader() { ctx.font = '7px Arial'; ctx.textAlign = 'center'; var colors = ['#000000', '#000000', '#ff0000', '#006fff', '#07c160', '#ff0000', '#006fff']; for (var i = 0; i < headers.length; i++) { var