t-comm
Version:
专业、稳定、纯粹的工具库
1,697 lines (1,666 loc) • 1.51 MB
JavaScript
import _typeof from '@babel/runtime/helpers/typeof';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import _regeneratorRuntime from '@babel/runtime/regenerator';
import axios from 'axios';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
import _createClass from '@babel/runtime/helpers/createClass';
import * as fs from 'fs';
import fs__default from 'fs';
import * as path from 'path';
import path__default from 'path';
import _toArray from '@babel/runtime/helpers/toArray';
function parseOptions$4(options) {
var key = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'msg';
var innerOptions = {};
if (typeof options === 'string') {
innerOptions = _defineProperty({}, key, options);
} 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) {
var method = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'info';
if (!mAegisV2 || !options || !method) return;
try {
var innerOptions = parseOptions$4(options, 'msg');
mAegisV2[method](Object.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$4(options, 'name');
if (!innerOptions.name) return;
mAegisV2.reportEvent(Object.assign({}, innerOptions));
} catch (err) {
console.log('[reportEvent] error', err);
}
}
/**
* 88.合并两个有序数组
*
* https://leetcode.cn/problems/merge-sorted-array/description/?envType=study-plan-v2&envId=top-interview-150
*
* 双指针解法
* - 将两个数组看成队列,每次从数组头部取出较小数字放到结果中
*
* - 时间复杂度 O(m + n)
* - 空间复杂度 O(m + n)
*
* @example
* ```ts
* const nums1 = [1, 3, 9, 0, 0, 0, 0];
* const nums2 = [2, 4, 5, 9];
* mergeTwoSortedArrayV1(nums1, nums2, 3, 4);
* // [1, 2, 3, 4, 5, 9, 9]
*
* const a = [1, 2, 3, 0, 0, 0];
* const b = [2, 5, 6];
* mergeTwoSortedArrayV1(a, b, 3, 3);
* // [1, 2, 2, 3, 5, 6]
* ```
*/
function mergeTwoSortedArrayV1() {
var nums1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var nums2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var m = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var n = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var p1 = 0;
var p2 = 0;
var temp = [];
while (p1 < m || p2 < n) {
if (p1 === m || nums1[p1] > nums2[p2]) {
temp.push(nums2[p2]);
p2 += 1;
} else if (p2 === n || nums1[p1] <= nums2[p2]) {
temp.push(nums1[p1]);
p1 += 1;
}
}
for (var i = 0; i < m + n; i++) {
// eslint-disable-next-line no-param-reassign
nums1[i] = temp[i];
}
return nums1;
}
/**
* 88.合并两个有序数组
*
* https://leetcode.cn/problems/merge-sorted-array/description/?envType=study-plan-v2&envId=top-interview-150
*
* 逆向双指针解法
* - 指针初始位置在尾部,每次向前移动
* - 不用临时数组 temp,因为不用担心前面的被覆盖
*
* - 时间复杂度 O(m + n)
* - 空间复杂度 O(1)
*
* @example
* ```ts
* const nums1 = [1, 3, 9, 0, 0, 0, 0];
* const nums2 = [2, 4, 5, 9];
* mergeTwoSortedArrayV2(nums1, nums2, 3, 4);
* // [1, 2, 3, 4, 5, 9, 9]
*
* const a = [1, 2, 3, 0, 0, 0];
* const b = [2, 5, 6];
* mergeTwoSortedArrayV2(a, b, 3, 3);
* // [1, 2, 2, 3, 5, 6]
* ```
*/
function mergeTwoSortedArrayV2() {
var nums1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var nums2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var m = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var n = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
var p1 = m - 1;
var p2 = n - 1;
var tail = m + n - 1;
while (p1 >= 0 || p2 >= 0) {
var cur = 0;
if (p1 === -1 || nums1[p1] <= nums2[p2]) {
cur = nums2[p2];
p2 -= 1;
} else if (p2 === -1 || nums1[p1] > nums2[p2]) {
cur = nums1[p1];
p1 -= 1;
}
// eslint-disable-next-line no-param-reassign
nums1[tail] = cur;
tail -= 1;
}
return nums1;
}
/**
*
* 27.移除元素
*
* https://leetcode.cn/problems/remove-element/description/?envType=study-plan-v2&envId=top-interview-150
*
* 双指针。
* - 右指针 right 指向当前将要处理的元素,左指针 left 指向下一个将要赋值的位置。
* - 如果右指针不等于 val,就将右指针指向的值赋值给左指针位置,左指针右移一位。
*
*
* - 时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多两次。
* - 空间复杂度:O(1)。我们只需要常数的空间保存若干变量
*
* @example
* ```ts
* removeElementInArrayV1([3, 2, 2, 3], 3); // 2
* removeElementInArrayV1([0, 1, 2, 2, 3, 0, 4, 2], 2); // 5
* ```
*/
function removeElementInArrayV1(nums, val) {
var left = 0;
var n = nums.length;
for (var right = 0; right < n; right++) {
if (nums[right] !== val) {
// eslint-disable-next-line no-param-reassign
nums[left] = nums[right];
left += 1;
}
}
return left;
}
/**
*
* 27.移除元素
*
* https://leetcode.cn/problems/remove-element/description/?envType=study-plan-v2&envId=top-interview-150
*
* 对撞指针。
* - 两个指针初始时分别位于数组的首尾,向中间移动遍历该序列。
* - 如果左指针 left 指向的元素等于 val,此时将右指针 right 指向的元素复制到左指针 left 的位置,然后右指针 right 左移一位。否则左指针 left 右移一位。
*
* - 时间复杂度:O(n),其中 n 为序列的长度。我们只需要遍历该序列至多一次。
* - 空间复杂度:O(1)。我们只需要常数的空间保存若干变量
*
* 第一种是快慢指针,第二种是对撞指针,同样是双指针,前者同向出发,因此用一个 for 循环实现遍历;后者前后出发,因此用 while 循环判断指针对撞时退出循环
*
* @example
* ```ts
* removeElementInArrayV2([3, 2, 2, 3], 3); // 2
* removeElementInArrayV2([0, 1, 2, 2, 3, 0, 4, 2], 2); // 5
* ```
*/
function removeElementInArrayV2(nums, val) {
var left = 0;
var right = nums.length - 1;
while (left <= right) {
if (nums[left] === val) {
// eslint-disable-next-line no-param-reassign
nums[left] = nums[right];
right -= 1;
} else {
left += 1;
}
}
return left;
}
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 Object.assign({
source: newSource,
target: target
}, parseOneReplaceConfig(item));
});
if (!importedList.length) {
acc.push(Object.assign(Object.assign({}, item), {
source: newSource,
sourceName: 'FAKE',
targetName: 'FAKE',
sourceType: IImportType.FAKE,
targetType: IImportType.FAKE
}));
} else {
acc.push.apply(acc, _toConsumableArray(list));
}
return acc;
}, []);
var newResult = result.reduce(function (acc, item) {
var source = item.source;
var list = source.map(function (sourceItem) {
return Object.assign(Object.assign({}, item), {
source: sourceItem
});
});
acc.push.apply(acc, _toConsumableArray(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 Object.assign(Object.assign({}, curOrigin), {
_type: 'OLD',
target: originSource,
targetName: curOrigin.imported,
targetType: curOrigin.type
});
}
return Object.assign(Object.assign(Object.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 [].concat(_toConsumableArray(nodeList), [oldNodeList]);
}
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));
}
/******************************************************************************
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.
***************************************************************************** */
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());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/**
* 获取 fs 模块
* @returns fs 模块
* @description 仅在 Node.js 环境中可用
* @example
* ```ts
* import { getFs } from 't-comm';
* const fs = getFs();
* fs.readFileSync('path/to/file', 'utf-8');
* ```
*/
function getFs() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('fs');
}
/**
* 获取 Node.js path 模块
* 动态导入 path 模块,避免在浏览器环境中引起错误
* @returns Node.js path 模块
* @example
* ```ts
* const path = getPath();
* const fullPath = path.resolve(__dirname, './file.txt');
* const basename = path.basename('/path/to/file.txt'); // 'file.txt'
* ```
*/
function getPath() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('path');
}
/**
* 同步递归收集目录下所有文件路径
* 递归遍历指定目录,收集所有文件的绝对路径到数组中
* @param {string} dirPath 目录路径
* @param {string[]} [fileList=[]] 用于累积结果的数组(可选,递归内部使用)
* @returns {string[]} 所有文件的绝对路径数组
* @example
* ```ts
* const files = collectFilesSync('/path/to/dir');
* // ['/path/to/dir/a.ts', '/path/to/dir/sub/b.ts', ...]
* ```
*/
function collectFilesSync() {
var dirPath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var fileList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
if (!getFs().existsSync(dirPath)) {
console.log('[Not Exists]', dirPath);
return [];
}
var items = getFs().readdirSync(dirPath);
items.forEach(function (item) {
var fullPath = getPath().join(dirPath, item);
var stat = getFs().statSync(fullPath);
if (stat.isDirectory()) {
collectFilesSync(fullPath, fileList); // 递归进入子目录
} else {
fileList.push(fullPath); // 将文件路径加入数组
}
});
return fileList;
}
/**
* 解析带注释的 json 文件
* @param content 原始文件内容
* @returns json数据
* @example
* ```ts
* const text = `{
* // 这是一个注释
* "name": "foo",
* "version": "1.0.0" // 末尾注释
* }`;
* parseCommentJson(text); // { name: 'foo', version: '1.0.0' }
* ```
*/
function parseCommentJson(content) {
var newContent = content.replace(/(?:\s+|^)\/\/[^\n]*/g, '');
var json = {};
try {
json = JSON.parse(newContent);
} catch (err) {}
return json;
}
/**
* 获取带注释的 json 文件内容
* @param file 文件路径
* @returns json数据
* @example
* ```ts
* // tsconfig.json 中可能含有 // 注释
* const config = readCommentJson('./tsconfig.json');
* console.log(config.compilerOptions);
* ```
*/
function readCommentJson(file) {
var content = getFs().readFileSync(file, {
encoding: 'utf-8'
});
return parseCommentJson(content);
}
/**
* 获取 Node.js 的 crypto 模块
* 这样可以避免在浏览器环境中直接导入 crypto 模块导致的错误
* @returns crypto 模块
* @example
* ```ts
* const crypto = getCrypto();
* const hash = crypto.createHash('md5').update('hello').digest('hex');
* ```
*/
function getCrypto() {
// 在浏览器环境中,这个函数不应该被调用
// 如果被调用,会抛出错误
// 在 Node.js 环境中,会正常返回 crypto 模块
return require('crypto');
}
/**
* 获取 os 模块
* @returns os 模块
* @description 仅在 Node.js 环境中可用
* @example
* ```ts
* import { getOs } from 't-comm';
* const os = getOs();
* const tmpDir = os.tmpdir();
* ```
*/
function getOs() {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('os');
}
/**
* 写入文件
* @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) {
var isJson = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var _a;
var fileData = isJson ? JSON.stringify(data, null, 2) : data;
var eol = getOs().EOL || '\n';
if (!((_a = fileData === null || fileData === void 0 ? void 0 : fileData.endsWith) === null || _a === void 0 ? void 0 : _a.call(fileData, eol))) {
fileData += eol;
}
getFs().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) {
var isJson = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var content = getFs().readFileSync(file, {
encoding: 'utf-8'
});
var result = content;
if (isJson) {
try {
result = JSON.parse(content);
} catch (e) {}
}
return result;
}
function isDirectory() {
var filePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
var stat = getFs().lstatSync(filePath);
return stat.isDirectory();
}
function ensureDir(dir) {
if (!getFs().existsSync(dir)) {
getFs().mkdirSync(dir, {
recursive: true
});
}
}
/**
* 计算本地文件的哈希值
* @param {string} filePath 文件路径
* @param {'md5' | 'sha1' | 'sha256'} [algorithm='md5'] 哈希算法
* @returns {string | null} 哈希值(hex 字符串);文件不存在或读取失败时返回 null
* @example
* ```ts
* const md5 = getLocalFileHash('/path/to/file');
* const sha256 = getLocalFileHash('/path/to/file', 'sha256');
* ```
*/
function getLocalFileHash(filePath) {
var algorithm = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'md5';
var fs = getFs();
if (!filePath || !fs.existsSync(filePath)) {
return null;
}
try {
var buffer = fs.readFileSync(filePath);
return getCrypto().createHash(algorithm).update(buffer).digest('hex');
} catch (e) {
return null;
}
}
/**
* 计算本地文件的 MD5
* @param {string} filePath 文件路径
* @returns {string | null} MD5 值(hex 字符串);文件不存在或读取失败时返回 null
* @example
* ```ts
* const md5 = getLocalFileMd5('/path/to/file');
* ```
*/
function getLocalFileMd5(filePath) {
return getLocalFileHash(filePath, 'md5');
}
/**
* 获取本地文件大小(字节数)
* @param {string} filePath 文件路径
* @returns {number | null} 文件大小(字节);文件不存在或读取失败时返回 null
* @example
* ```ts
* const size = getLocalFileSize('/path/to/file');
* ```
*/
function getLocalFileSize(filePath) {
var fs = getFs();
if (!filePath || !fs.existsSync(filePath)) {
return null;
}
try {
return fs.statSync(filePath).size;
} catch (e) {
return null;
}
}
/**
* 将时间戳格式化
* @param {number} timestamp
* @param {string} fmt
* @param {string} [defaultVal]
* @returns {string} 格式化后的日期字符串
* @example
*
* const stamp = new Date('2020-11-27 8:23:24').getTime();
*
* const res = timeStampFormat(stamp, 'yyyy-MM-dd hh:mm:ss')
*
* // 2020-11-27 08:23:24
*/
function timeStampFormat(timestamp, fmt, defaultVal) {
var whitePrefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
if (!timestamp) {
return defaultVal || '';
}
var date = new Date();
if ("".concat(timestamp).length === 10) {
timestamp *= 1000;
}
date.setTime(timestamp);
var o = {
'M+': date.getMonth() + 1,
'd+': date.getDate(),
'h+': date.getHours(),
'm+': date.getMinutes(),
's+': date.getSeconds(),
'q+': Math.floor((date.getMonth() + 3) / 3),
S: date.getMilliseconds() // 毫秒
};
var reg = /(y+)/;
if (whitePrefix) {
reg = new RegExp("(?:^|(?:[^".concat(whitePrefix, "y]))(y+)"));
}
var match = fmt.match(reg);
if (match === null || match === void 0 ? void 0 : match[1]) {
fmt = fmt.replace(match[1], "".concat(date.getFullYear()).slice(4 - match[1].length));
}
// eslint-disable-next-line no-restricted-syntax
for (var k in o) {
var _reg = new RegExp("(".concat(k, ")"));
if (whitePrefix) {
_reg = new RegExp("(?:^|(?:[^".concat(whitePrefix).concat(k[0], "]))(").concat(k, ")"));
}
match = fmt.match(_reg);
if (match === null || match === void 0 ? void 0 : match[1]) {
var _match = match,
_match$index = _match.index,
index = _match$index === void 0 ? 0 : _match$index;
var realIndex = whitePrefix ? index + match[0].length - match[1].length : index;
var str = "".concat(o[k]);
var len = match[1].length;
var replacePart = len === 1 ? str : "00".concat(str).slice("".concat(str).length);
fmt = fmt.slice(0, realIndex) + replacePart + fmt.slice(realIndex + len);
// fmt = fmt.replace(
// match[1],
// match[1].length === 1 ? str : `00${str}`.slice(`${str}`.length),
// );
}
}
if (whitePrefix) {
fmt = fmt.replace(new RegExp(whitePrefix, 'g'), '');
}
return fmt;
}
/**
* 将日期格式化
* @param {Date} date
* @param {string} format
* @returns {string} 格式化后的日期字符串
* @example
*
* const date = new Date('2020-11-27 8:23:24');
*
* const res = dateFormat(date, 'yyyy-MM-dd hh:mm:ss')
*
* // 2020-11-27 08:23:24
*/
function dateFormat(date, fmt) {
var timestamp = new Date(date).getTime();
return timeStampFormat(timestamp, fmt);
}
var LOG_DIR = 'log';
/**
* 内部复制函数,用于复制文件和目录
* @param src - 源路径
* @param dist - 目标路径
* @private
*/
function innerCopy(src, dist) {
// statSync 的结果除了 isFile() 和 isDirectory(),还可能是
// 符号链接(symlink)、块设备、字符设备、FIFO 等
if (!getFs().statSync(src).isDirectory()) {
return;
}
var paths = getFs().readdirSync(src);
paths.forEach(function (p) {
var tSrc = "".concat(src, "/").concat(p);
var tDist = "".concat(dist, "/").concat(p);
var stat = getFs().statSync(tSrc);
if (stat.isFile()) {
// 判断是文件还是目录
writeFileSync(tDist, readFileSync(tSrc));
} else if (stat.isDirectory()) {
innerCopyDir(tSrc, tDist); // 当是目录时,递归复制
}
});
}
/**
* 内部递归复制目录函数
* 复制目录、子目录,及其中的文件
* @param src - 要复制的源目录路径
* @param dist - 复制到的目标目录路径
* @private
*/
function innerCopyDir(src, dist) {
var b = getFs().existsSync(dist);
if (!b) {
mkDirsSync(dist); // 创建目录
}
innerCopy(src, dist);
}
/**
* 递归创建目录(同步方法)
* 如果目录已存在则直接返回,否则递归创建父目录
* @param dirname - 要创建的目录路径
* @returns 创建成功返回 true
* @example
* ```ts
* mkDirsSync('/path/to/new/directory');
* ```
*/
function mkDirsSync(dirname) {
if (getFs().existsSync(dirname)) {
return true;
}
if (mkDirsSync(getPath().dirname(dirname))) {
getFs().mkdirSync(dirname);
return true;
}
return false;
}
/**
* 拷贝目录以及子文件
* 递归复制整个目录结构,包括所有子目录和文件
* @param src - 源目录路径
* @param dist - 目标目录路径
* @param callback - 可选的回调函数,复制完成后执行
* @example
* ```ts
* copyDir('/source/path', '/target/path', () => {
* console.log('复制完成');
* });
* ```
*/
function copyDir(src, dist, callback) {
innerCopyDir(src, dist);
if (callback) {
callback();
}
}
/**
* 删除目录及其所有内容
* 递归删除目录下的所有文件和子目录
* @param tPath - 要删除的目录路径
* @example
* ```ts
* deleteFolder('/path/to/folder');
* ```
*/
function deleteFolder(tPath) {
var files = [];
if (getFs().existsSync(tPath)) {
files = getFs().readdirSync(tPath);
files.forEach(function (file) {
var curPath = "".concat(tPath, "/").concat(file);
if (getFs().statSync(curPath).isDirectory()) {
deleteFolder(curPath);
} else {
getFs().unlinkSync(curPath);
}
});
getFs().rmdirSync(tPath);
}
}
/**
* 递归删除空目录
* 从指定路径开始,递归删除所有空目录(不删除包含文件的目录)
* @param tPath - 要检查和删除的目录路径
* @param level - 当前递归层级,默认为 0(根层级不会被删除)
* @example
* ```ts
* rmEmptyDir('/path/to/check');
* ```
*/
function rmEmptyDir(tPath) {
var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var files = getFs().readdirSync(tPath);
if (files.length > 0) {
var tempFile = 0;
files.forEach(function (file) {
tempFile += 1;
rmEmptyDir("".concat(tPath, "/").concat(file), level + 1);
});
if (tempFile === files.length && level !== 0) {
getFs().rmdirSync(tPath);
}
} else {
level !== 0 && getFs().rmdirSync(tPath);
}
}
/**
* 递归删除文件夹(可配置是否删除文件)
* 递归遍历目录,根据配置决定是否删除文件,并删除空目录
* @param path - 要处理的目录路径
* @param options - 配置选项
* @param options.deleteFile - 是否删除文件,默认为 false
* @param options.log - 是否输出日志,默认为 false
* @example
* ```ts
* // 只删除空目录
* deleteFolderRecursive('/path/to/folder');
*
* // 删除所有文件和目录
* deleteFolderRecursive('/path/to/folder', { deleteFile: true, log: true });
* ```
*/
function deleteFolderRecursive(path) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
deleteFile: false,
log: false
};
var _a, _b;
var deleteFile = (_a = options.deleteFile) !== null && _a !== void 0 ? _a : false;
var log = (_b = options.log) !== null && _b !== void 0 ? _b : false;
if (getFs().existsSync(path)) {
var list = getFs().readdirSync(path);
list.forEach(function (file) {
var curPath = "".concat(path, "/").concat(file);
if (getFs().statSync(curPath).isDirectory()) {
// recurse
deleteFolderRecursive(curPath, options);
} else {
// delete file
if (deleteFile) {
getFs().unlinkSync(curPath);
}
}
});
var remaining = getFs().readdirSync(path);
if (!remaining.length) {
if (log) {
console.log('>>> delete: ', path);
}
getFs().rmdirSync(path);
}
}
}
/**
* 拷贝单个文件
* 将文件从源路径复制到目标路径
* @param from - 源文件路径
* @param to - 目标文件路径
* @returns 写入操作的结果
* @example
* ```ts
* copyFile('/source/file.txt', '/target/file.txt');
* ```
*/
function copyFile(from, to) {
return writeFileSync(to, readFileSync(from));
}
/**
* 递归遍历文件夹,并对每个文件执行回调函数
* 遍历目录树,对每个文件(非目录)执行指定的回调函数
* @param cb - 回调函数,接收文件路径作为参数
* @param tPath - 要遍历的文件夹或文件路径
* @example
* ```ts
* traverseFolder((filePath) => {
* console.log('处理文件:', filePath);
* }, '/path/to/folder');
* ```
*/
function traverseFolder(cb, tPath) {
if (getFs().statSync(tPath).isDirectory()) {
var files = getFs().readdirSync(tPath);
files.forEach(function (file) {
var curPath = getPath().resolve(tPath, file);
// `${tPath}/${file}`;
traverseFolder(cb, curPath);
});
} else {
cb(tPath);
}
}
/**
* 从日志目录读取 JSON 文件
* 读取 ./log 目录下的 JSON 文件内容
* @param file - 文件名(相对于 log 目录)
* @param defaultContent - 文件不存在时返回的默认内容,默认为 '{}'
* @returns JSON 文件内容字符串
* @example
* ```ts
* const content = readJsonLog('data.json', '[]');
* ```
*/
function readJsonLog(file) {
var defaultContent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '{}';
var filePath = "./".concat(LOG_DIR, "/").concat(file);
if (!getFs().existsSync(filePath)) {
createLogDir();
return defaultContent;
}
return readFileSync(filePath) || defaultContent;
}
/**
* 获取 JSON 日志目录的绝对路径
* @returns 日志目录的绝对路径
* @example
* ```ts
* const logDir = getJsonLogDir();
* console.log(logDir); // /path/to/project/log
* ```
*/
function getJsonLogDir() {
return getPath().resolve(process.cwd(), './log');
}
/**
* 将 JSON 对象保存到日志文件
* 将对象序列化为 JSON 并保存到 ./log 目录下
* @param content - 要保存的对象内容
* @param file - 文件名(相对于 log 目录)
* @param needLog - 是否需要保存日志,默认为 true
* @example
* ```ts
* saveJsonToLog({ status: 'success', data: [1, 2, 3] }, 'result.json');
* ```
*/
function saveJsonToLog(content, file) {
var needLog = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
if (!needLog) return;
createLogDir();
writeFileSync("./".concat(LOG_DIR, "/").concat(file), content, true);
}
/**
* 将内容追加保存到日志文件(支持保留历史记录)
* 以数组形式保存多条日志记录,每条记录包含时间戳和数据,支持限制最大记录数
* @param content - 要保存的内容
* @param file - 文件名(相对于 log 目录)
* @param options - 配置选项
* @param options.needLog - 是否需要保存日志,默认为 true
* @param options.max - 最大保留记录数,默认为 10
* @example
* ```ts
* saveJsonToLogMore({ action: 'upload', status: 'success' }, 'history.json', {
* needLog: true,
* max: 20
* });
* ```
*/
function saveJsonToLogMore(content, file, options) {
var _a, _b;
var needLog = (_a = options === null || options === void 0 ? void 0 : options.needLog) !== null && _a !== void 0 ? _a : true;
var max = (_b = options === null || options === void 0 ? void 0 : options.max) !== null && _b !== void 0 ? _b : 10;
if (!needLog) return;
createLogDir();
var filePath = "./log/".concat(file);
var beforeContent = [];
var newContent = [{
logTime: timeStampFormat(Date.now(), 'yyyy-MM-dd hh:mm:ss'),
data: content
}];
if (getFs().existsSync(filePath)) {
try {
beforeContent = readFileSync(filePath, true).logList || [];
} catch (err) {
beforeContent = [];
}
}
if (beforeContent && Array.isArray(beforeContent)) {
var _newContent;
(_newContent = newContent).push.apply(_newContent, _toConsumableArray(beforeContent));
}
newContent = newContent.slice(0, max);
try {
getFs().writeFile(filePath, JSON.stringify({
logList: newContent
}, null, 2), {
encoding: 'utf-8'
}, function () {});
} catch (err) {}
}
/**
* 从日志目录读取并解析 JSON 文件
* 读取 ./log 目录下的 JSON 文件并解析为对象
* @param file - 文件名(相对于 log 目录)
* @returns 解析后的 JSON 对象,解析失败或文件不存在时返回空对象
* @example
* ```ts
* const data = getJsonFromLog('config.json');
* console.log(data);
* ```
*/
function getJsonFromLog(file) {
var filePath = "./".concat(LOG_DIR, "/").concat(file);
var data = {};
if (!getFs().existsSync(filePath)) {
console.log('[getJsonFromLog] no exist');
} else {
var originFile = getFs().readFileSync(filePath, {
encoding: 'utf-8'
});
try {
data = JSON.parse(originFile);
} catch (err) {}
}
return data;
}
/**
* 创建日志目录
* 如果 ./log 目录不存在则创建
* @private
*/
function createLogDir() {
if (!getFs().existsSync("./".concat(LOG_DIR))) {
getFs().mkdirSync("./".concat(LOG_DIR));
}
}
/**
* 从文件路径中提取文件名(不含扩展名)
* @param file - 文件路径
* @returns 不含扩展名的文件名
* @example
* ```ts
* const name = getFileName('/path/to/file.txt');
* console.log(name); // 'file'
* ```
*/
function getFileName(file) {
var basename = getPath().basename(file);
var extname = getPath().extname(file);
var fileName = basename.replace(new RegExp("".concat(extname, "$")), '');
return fileName;
}
/**
* 解析 JSON 字符串为对象
* 安全地解析 JSON 字符串,解析失败时输出错误信息并返回空对象
* @param content - JSON 字符串内容
* @param file - 文件路径(用于错误日志)
* @returns 解析后的对象,解析失败时返回空对象
* @example
* ```ts
* const data = readJson('{"name":"test"}', 'config.json');
* console.log(data); // { name: 'test' }
* ```
*/
function readJson(content, file) {
var data = {};
try {
data = JSON.parse(content);
} catch (e) {
console.error('>>> read json error: ', file);
}
return data;
}
function checkFileBaseMinimatch(_ref) {
var file = _ref.file,
include = _ref.include,
exclude = _ref.exclude,
minimatch = _ref.minimatch;
var curInclude = Array.isArray(include) ? include : [include];
var curExclude = Array.isArray(exclude) ? exclude : [exclude];
return curInclude.some(function (pattern) {
return minimatch(file, pattern);
}) && !curExclude.some(function (pattern) {
return minimatch(file, pattern);
});
}
function _createForOfIteratorHelper$x(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$x(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray$x(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$x(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$x(r, a) : void 0; } }
function _arrayLikeToArray$x(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
/**
* 获取审核人
* @param params 参数
* @returns 审核人
*
* @example
* ```ts
* getAuditorFromRainbowConfig({
* rainbowConfig: { "pmd-mobile/match/*": "gg", "pmd-mobile/convert-cross": "gg" },
* checkKeyList: [ 'pmd-mobile/match/gp/gp-hor', 'pmd-mobile/match/gp' ],
* minimatch: require('minimatch'),
* minimatchKey: 'pmd-mobile/match/gp',
* })
* ```
*/
function getAuditorFromRainbowConfig(_ref) {
var rainbowConfig = _ref.rainbowConfig,
checkKeyList = _ref.checkKeyList,
minimatch = _ref.minimatch,
minimatchKey = _ref.minimatchKey;
var _iterator = _createForOfIteratorHelper$x(checkKeyList),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var key = _step.value;
if (rainbowConfig[key]) {
return rainbowConfig[key];
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
var matchedGlob = Object.keys(rainbowConfig).find(function (item) {
return minimatch(minimatchKey, item);
});
if (matchedGlob) {
return rainbowConfig[matchedGlob];
}
return '';
}
/** 判断审核人是否有效(空或 'NONE' 均视为无需审核) */
function isValidAuditor(auditor) {
return !!auditor && auditor !== 'NONE';
}
/** 解析配置数据源:支持文件路径(同步读取)或异步获取函数 */
function resolveConfig(configSource) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var _t;
return _regeneratorRuntime.wrap(function (_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (!(typeof configSource === 'function')) {
_context.next = 2;
break;
}
_context.next = 1;
return configSource();
case 1:
_t = _context.sent;
_context.next = 3;
break;
case 2:
_t = readFileSync(configSource, true);
case 3:
return _context.abrupt("return", _t);
case 4:
case "end":
return _context.stop();
}
}, _callee);
}));
}
/**
* 统一审核人获取方法,支持 rainbow / json / static 三种模式
*
* @example rainbow 模式 - 文件路径
* ```ts
* const { auditor, shouldAudit } = await getAuditor({
* type: 'rainbow',
* configSource: '/data/h5_publish_auditor.json',
* rainbowOptions: { projectName: 'pmd-mobile/match/gp', subProjectName: 'gp-hor', minimatch },
* });
* ```
*
* @example rainbow 模式 - 异步获取数据
* ```ts
* const { auditor, shouldAudit } = await getAuditor({
* type: 'rainbow',
* configSource: async () => fetchRainbowConfig(),
* rainbowOptions: { projectName: 'pmd-mobile/match/gp', subProjectName: 'gp-hor', minimatch },
* });
* ```
*
* @example json 模式(NPM/组件库发布)
* ```ts
* const { auditor, shouldAudit } = await getAuditor({
* type: 'json',
* configSource: '/data/library_publish_auditor.json',
* jsonOptions: { projectName: 'my-lib', key: 'patch' },
* });
* ```
*
* @example static 模式(灰度发布 / 回滚)
* ```ts
* const { auditor, shouldAudit } = await getAuditor({
* type: 'static',
* staticAuditorList: ['novlan1', 'lee'],
* });
* ```
*
* @example 跳过审核(如非生产环境)
* ```ts
* const { auditor, shouldAudit } = await getAuditor({
* type: 'static',
* skipAudit: !isProd,
* });
* ```
*/
function getAuditor(options) {
var _a;
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
var type, configSource, rainbowOptions, jsonOptions, staticAuditorList, _options$skipAudit, skipAudit, projectName, subProjectName, minimatch, auditKey, rainbowConfig, auditor, _projectName, key, data, _auditor, _auditor2;
return _regeneratorRuntime.wrap(function (_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
type = options.type, configSource = options.configSource, rainbowOptions = options.rainbowOptions, jsonOptions = options.jsonOptions, staticAuditorList = options.staticAuditorList, _options$skipAudit = options.skipAudit, skipAudit = _options$skipAudit === void 0 ? false : _options$skipAudit; // 跳过审核
if (!skipAudit) {
_context2.next = 1;
break;
}
return _context2.abrupt("return", {
auditor: '',
shouldAudit: false
});
case 1:
if (!(type === 'rainbow')) {
_context2.next = 4;
break;
}
if (!(!rainbowOptions || !configSource)) {
_context2.next = 2;
break;
}
return _context2.abrupt("return", {
auditor: '',
shouldAudit: false
});
case 2:
projectName = rainbowOptions.projectName, subProjectName = rainbowOptions.subProjectName, minimatch = rainbowOptions.minimatch;
auditKey = "".concat(projectName, "##").concat(subProjectName);
_context2.next = 3;
return resolveConfig(configSource);
case 3:
rainbowConfig = _context2.sent;
console.log('[getAuditor][rainbowConfig]', rainbowConfig);
auditor = getAuditorFromRainbowConfig({
rainbowConfig: rainbowConfig,
checkKeyList: [auditKey, projectName],
minimatch: minimatch,
minimatchKey: projectName
});
console.log('[getAuditor][auditor]', auditor);
return _context2.abrupt("return", {
auditor: auditor || '',
shouldAudit: isValidAuditor(auditor || '')
});
case 4:
if (!(type === 'json')) {
_context2.next = 7;
break;
}
if (!(!jsonOptions || !configSource)) {
_context2.next = 5;
break;
}
return _context2.abrupt("return", {
auditor: '',
shouldAudit: false
});
case 5:
_projectName = jsonOptions.projectName, key = jsonOptions.key;
_context2.next = 6;
return resolveConfig(configSource);
case 6:
data = _context2.sent;
_auditor = ((_a = data === null || data === void 0 ? void 0 : data[_projectName]) === null || _a === void 0 ? void 0 : _a[key]) || '';
return _context2.abrupt("return", {
auditor: _auditor,
shouldAudit: isValidAuditor(_auditor)
});
case 7:
if (!(type === 'static')) {
_context2.next = 8;
break;
}
_auditor2 = (staticAuditorList || []).join(',');
return _context2.abrupt("return", {
auditor: _auditor2,
shouldAudit: isValidAuditor(_auditor2)
});
case 8:
return _context2.abrupt("return", {
auditor: '',
shouldAudit: false
});
case 9:
case "end":
return _context2.stop();
}
}, _callee2);
}));
}
/**
* 转义审核描述中的反引号,防止在企微消息中出错
*
* @example
* ```ts
* escapeAuditDesc('修复`bug`') // => '修复\\`bug\\`'
* ```
*/
function escapeAuditDesc(desc) {
return (desc || '').replace(/`/g, '\\`');
}
/**
* 获取 rtx 拼接的提及字符串
* @param rawStr 原始字符串,比如 `foo,bar`
* @returns 处理后的字符串,比如 <@foo><@bar>
* @example
* ```ts
* getMentionRtx('foo,bar'); // '<@foo><@bar>'
* getMentionRtx('foo;bar'); // '<@foo><@bar>'
* getMentionRtx('foo'); // '<@foo>'
* getMentionRtx(''); // ''
* ```
*/
function getMentionRtx() {
var rawStr = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if (!rawStr) {
return '';
}
var result = rawStr.split(/,|;/).map(function (item) {
return "<@".concat(item, ">");
}).join('');
return result;
}
function getRtxInfoV2(defaultRtx) {
return new Promise(function (resolve, reject) {
if (window.location.host.startsWith('localhost')) {
resolve({
rtx: defaultRtx || 'developer'
});
return;
}
axios({
url: "".concat(window.location.protocol, "//").concat(window.location.host, "/ts:auth/tauth/info.ashx"),
method: 'get'
}).then(function (response) {
if (response.data.EngName) {
resolve(Object.assign(Object.assign({}, response.data), {
rtx: response.data.EngName
}));
}
})["catch"](function (err) {
reject(err);
});
});
}
/**
* 获取rtx信息
* @private
* @example
* ```ts
* getRtxInfo().then((info) => {
* console.log(info); // { rtx: 'xxx', ... }
* });
* ```
*/
function getRtxInfo() {
return new Promise(function (resolve, reject) {
var cached = localStorage.getItem('AEGIS_RTX');
if (cached) {
resolve(cached);
return;
}
var url = "".concat(location.origin, "/ts:auth/tauth/info.ashx");
fetch(url).then(function (response) {
if (response.status === 200) {
return response.json();
}
return {};
}).then(function (data) {
resolve(data);
})["catch"](function (err) {
reject(err);
});
});
}
/**
* 构建审核通知内容数组
*
* 统一拼接审核通知消息,各流水线只需传入标题和差异化字段即可。
*
* @example H5 发布
* ```ts
* const content = buildAuditContent({
* title: '【H5发布审核】',
* projectName: 'pmd-mobile/match/gp',
* creator: 'novlan1',
* auditor: 'junshao',
* buildUrl: 'https://devops.woa.com/xxx',
* extraLines: [
* `子工程:\`gp-hor\``,
* `灰度比例:50%`,
* ],
* });
* ```
*
* @example 回滚审核
* ```ts
* const content = buildAuditContent({
* title: '【`回滚`审核】',
* projectName: 'pmd-mobile/match/gp',
* creator: 'novlan1',
* auditor: 'junshao',
* buildUrl: 'https://devops.woa.com/xxx',
* extraLines: [`子工程:\`gp-hor\``],
* });
* ```
*/
function buildAuditContent(options) {
var title = options.title,
projectName = options.projectName,
creator = options.creator,
auditor = options.auditor,
buildUrl = options.buildUrl,
_options$extraLines = options.extraLines,
extraLines = _options$extraLines === void 0 ? [] : _options$extraLines;
var auditorStr = getMentionRtx(auditor || '');
var titleLine = projectName ? "".concat(title, "\u9879\u76EE\uFF1A`").concat(projectName, "`") : title;
return [titleLine].concat(_toConsumableArray(extraLines), ["\u53D1\u8D77\u4EBA\uFF1A<@".concat(creator, ">"), "\u5BA1\u6838\u4EBA\uFF1A".concat(auditorStr), "[".concat(buildUrl, "](").concat(buildUrl, ")")]);
}
/**
* 从审核意见中提取真实审核人
*
* 当审核由 pmd-mcp 等自动化工具代为操作时,审核意见中会携带真实审核人信息,
* 格式为 "by pmd-mcp, from novlan1)",此函数提取其中的真实用户名。
*
* @param suggest - 审核意见字符串
* @returns 提取到的审核人用户名,未匹配则返回空字符串
*
* @example
* ```ts
* getReviewerFromSuggest('by pmd-mcp, from novlan1)') // => 'novlan1'
* getReviewerFromSuggest('by pmd-mcp, from novlan1') // => 'novlan1'
* getReviewerFromSuggest('LGTM') // => ''
* getReviewerFromSuggest('') // => ''
* ```
*/
function getReviewerFromSuggest(suggest) {
var match = suggest === null || suggest === void 0 ? void 0 : suggest.match(/from\s+([a-zA-Z0-9_]+)\s*\)?/);
return (match === null || match === void 0 ? void 0 : match[1]) || '';
}
var STATUS_MAP = {
ABORT: 'ABORT',
PROCESS: 'PROCESS'
};
/**
* 统一审核结果检查
*
* 检查审核结果,通过则 resolve,驳回则发送企微通知并 reject。
* 适用于 H5 发布、组件库发布等所有需要审核的流水线。
*
* @example H5 发布
* ```ts
* const { batchSendWxRobotMarkdown, checkAuditResult } = require('t-comm');
*
* await checkAuditResult({
* resultInfo,
* title: '【H5发布】',
* contentLines: [`项目: \`my-project\``, `子工程:\`my-sub\``],
* creator: 'novlan1',
* auditDesc: '需求发布',
* webhookUrl: '0482249e-bf24-4168-b3e2-f72d012840c2',
* sendMarkdown: batchSendWxRobotMarkdown,
* });
* ```
*/
function checkAuditResult(options) {
return __awaiter(this, void 0, void 0, /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
var resultInfo, title, contentLines, creator, auditDesc, webhookUrl, sendMarkdown, isPass, realReviewer, symbol, content, _t;
return _regeneratorRuntime.wrap(function (_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
resultInfo = options.resultInfo, title = options.title, contentLines = options.contentLines, creator = options.creator, auditDesc = options.auditDesc, webhookUrl = options.webhookUrl, sendMarkdown = options.sendMarkdown;
console.log('[checkAuditResult][resultInfo]', resultInfo);
isPass = resultInfo.status === STATUS_MAP.PROCESS;
realReviewer = getReviewerFromSuggest(resultInfo.suggest) || resultInfo.reviewer;
symbol = isPass ? '✅' : '❌';
if (!isPass) {
_context.next = 1;
break;
}
console.log('[checkAuditResult][PASS]');
return _context.abrupt("return");
case 1:
content = ["".concat(symbol).concat(title, "\u5BA1\u6838\u7ED3\u679C\uFF1A`").concat(isPass ? '通过' : '驳回', "`"), "\u5BA1\u6838\u610F\u89C1\uFF1A`".concat(resultInfo.suggest || '无', "`"), "\u5BA1\u6838\u4EBA\uFF1A<@".concat(realReviewer, ">")].concat(_toConsumableArray(contentLines), ["\u53D1\u5E03\u539F\u56E0\uFF1A`".concat(auditDesc, "`"), "\u53D1\u8D77\u4EBA\uFF1A<@".concat(creator, ">"), "[\u8BE6\u60C5](".concat(resultInfo.bkBuildUrl || '', ")")]).join(',');
_context.prev = 2;
_context.next = 3;
return sendMarkdown({
content: content,
chatId: ['ALL'],
webhookUrl: webhookUrl
});
case 3:
_context.next = 5;
break;
case 4:
_context.prev = 4;
_t = _context["catch"](2);
console.error('[checkAuditResult][sendMarkdown error]', _t);
case 5:
throw new Error('Audit Failed');
case 6:
case "end":
return _context.stop();
}
}, _callee, null, [[2, 4]]);
}));
}
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);