t-comm
Version:
专业、稳定、纯粹的工具库
390 lines (387 loc) • 15.7 kB
JavaScript
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
import fs__default from 'fs';
import path__default from 'path';
import { randomString } from '../string/random.mjs';
import { pascalCase } from '../string/string.mjs';
import { getGlob } from '../third-party/glob.mjs';
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(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(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(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(r, a) : void 0; } }
function _arrayLikeToArray(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; }
/**
* 生成 PascalCase 匹配正则(前后必须是非单词字符)
* @param {string} value - kebab-case 名称
* @returns {RegExp}
* @example
* ```ts
* const reg = getComponentPascalReg('press-icon');
* 'use <PressIcon/>'.match(reg); // ['PressIcon']
* ```
*/
function getComponentPascalReg(value) {
return new RegExp("(?<=\\W)(".concat(pascalCase(value), ")(?=\\W)"), 'g');
}
/**
* 生成三阶段重命名配置(plus -> temp, key -> plus, temp -> key)
* @param {string[]} rawList - 组件名列表,如 ['dialog', 'icon']
* @param {string[]} [extraList=[]] - 额外需要重命名的组件名列表
* @returns {{ renameConfig: Object, renameConfig2: Object, renameConfig3: Object }}
* @example
* ```ts
* const { renameConfig, renameConfig2, renameConfig3 } = getThreeStageRenameConfig(['dialog', 'icon']);
* // renameConfig: { 'press-dialog-plus': '<random>', 'press-icon-plus': '<random>' }
* // renameConfig2: { 'press-dialog': 'press-dialog-plus', 'press-icon': 'press-icon-plus' }
* // renameConfig3: { '<random>': 'press-dialog', '<random>': 'press-icon' }
* ```
*/
function getThreeStageRenameConfig(rawList) {
var extraList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var renameConfig = {};
var renameConfig2 = {};
var renameConfig3 = {};
var iRawList = [].concat(_toConsumableArray(rawList), _toConsumableArray(extraList));
var _iterator = _createForOfIteratorHelper(iRawList),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var item = _step.value;
var plusKey = "press-".concat(item, "-plus");
var key = "press-".concat(item);
var tempKey = randomString(6);
renameConfig[plusKey] = tempKey;
renameConfig2[key] = plusKey;
renameConfig3[tempKey] = key;
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return {
renameConfig: renameConfig,
renameConfig2: renameConfig2,
renameConfig3: renameConfig3
};
}
/**
* 生成 meta config(如 component-config.json)的 PascalCase 替换规则
* @param {string[]} rawList - 组件名列表
* @param {string[]} dirList - 目标文件 glob 列表
* @returns {Array<{ list: Array, dirList: string[] }>}
* @example
* ```ts
* const rules = getMetaConfigPascalReplaceRules(
* ['dialog', 'icon'],
* ['src/component-config.json'],
* );
* // rules 为三阶段替换规则数组,供 batchReplaceFileContent 使用
* ```
*/
function getMetaConfigPascalReplaceRules(rawList, dirList) {
var list = [];
var list2 = [];
var list3 = [];
var _iterator2 = _createForOfIteratorHelper(rawList),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var item = _step2.value;
var plusKey = "".concat(item, "-plus");
var key = "".concat(item);
var tempKey = randomString(6);
var preAndPostfixList = [['"', '"'], [' ', ' ']];
for (var _i = 0, _preAndPostfixList = preAndPostfixList; _i < _preAndPostfixList.length; _i++) {
var prefix = _preAndPostfixList[_i];
list.push(["".concat(prefix[0]).concat(pascalCase(plusKey)).concat(prefix[1]), "".concat(prefix[0]).concat(tempKey).concat(prefix[1])]);
list2.push(["".concat(prefix[0]).concat(pascalCase(key)).concat(prefix[1]), "".concat(prefix[0]).concat(pascalCase(plusKey)).concat(prefix[1])]);
list3.push(["".concat(prefix[0]).concat(tempKey).concat(prefix[1]), "".concat(prefix[0]).concat(pascalCase(key)).concat(prefix[1])]);
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return [{
list: list,
dirList: dirList
}, {
list: list2,
dirList: dirList
}, {
list: list3,
dirList: dirList
}];
}
/**
* 生成文件内容的三阶段替换规则(kebab-case + PascalCase + 类名)
* @param {string[]} rawList - 组件名列表
* @param {string[]} dirList - 目标文件 glob 列表
* @param {Object} [options={}] - 可选配置
* @param {string[]} [options.needClassReplaceList=[]] - 需要额外替换类名的组件列表
* @returns {Array<{ list: Array, dirList: string[] }>}
* @example
* ```ts
* const rules = getComponentContentReplaceRules(
* ['dialog', 'icon'],
* ['src/**\/*.{ts,vue,less}'],
* { needClassReplaceList: ['icon'] },
* );
* batchReplaceFileContent(rules);
* ```
*/
function getComponentContentReplaceRules(rawList, dirList) {
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var _options$needClassRep = options.needClassReplaceList,
needClassReplaceList = _options$needClassRep === void 0 ? [] : _options$needClassRep;
var list = [];
var list2 = [];
var list3 = [];
// kebab-case 前后缀匹配规则
var preAndPostfixList = [['/', '/'], ['/', '\''], ['/', '"'], ['/', '.vue'], ['<', ''], ['</', '>']];
var _iterator3 = _createForOfIteratorHelper(rawList),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var item = _step3.value;
var plusKey = "press-".concat(item, "-plus");
var key = "press-".concat(item);
var tempKey = randomString(6);
var tempKey2 = randomString(6);
// kebab-case 替换
var _iterator5 = _createForOfIteratorHelper(preAndPostfixList),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var prefix = _step5.value;
list.push(["".concat(prefix[0]).concat(plusKey).concat(prefix[1]), "".concat(prefix[0]).concat(tempKey).concat(prefix[1])]);
list2.push(["".concat(prefix[0]).concat(key).concat(prefix[1]), "".concat(prefix[0]).concat(plusKey).concat(prefix[1])]);
list3.push(["".concat(prefix[0]).concat(tempKey).concat(prefix[1]), "".concat(prefix[0]).concat(key).concat(prefix[1])]);
}
// PascalCase 替换(使用正则)
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
list.push([getComponentPascalReg(plusKey), pascalCase(tempKey2)]);
list.push([getComponentPascalReg(key), pascalCase(plusKey)]);
list.push([getComponentPascalReg(tempKey2), pascalCase(key)]);
}
// CSS 类名替换规则
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
var classPrefixList = [['.', ' '], ['.', ','], ['.', '-'], ['', ';'], ['', '__'], ['', '--'], ['\'', '\''] // press-icon-plus (iconPrefix)
];
var _iterator4 = _createForOfIteratorHelper(needClassReplaceList),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var _item = _step4.value;
var _plusKey = "press-".concat(_item, "-plus");
var _key = "press-".concat(_item);
var _tempKey = randomString(6);
var _iterator6 = _createForOfIteratorHelper(classPrefixList),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var _prefix = _step6.value;
list.push(["".concat(_prefix[0]).concat(_plusKey).concat(_prefix[1]), "".concat(_prefix[0]).concat(_tempKey).concat(_prefix[1])]);
list2.push(["".concat(_prefix[0]).concat(_key).concat(_prefix[1]), "".concat(_prefix[0]).concat(_plusKey).concat(_prefix[1])]);
list3.push(["".concat(_prefix[0]).concat(_tempKey).concat(_prefix[1]), "".concat(_prefix[0]).concat(_key).concat(_prefix[1])]);
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
return [{
list: list,
dirList: dirList
}, {
list: list2,
dirList: dirList
}, {
list: list3,
dirList: dirList
}];
}
/**
* 批量替换文件内容(性能优化版)
* 将同 dirList 的规则合并,每个文件只读写一次
* @param {Array<{ list: Array, dirList: string|string[] }>} replaceList - 替换规则列表
* @example
* ```ts
* batchReplaceFileContent([
* {
* list: [
* ['<PressIconPlus', '<PressIcon'],
* [/press-icon-plus/g, 'press-icon'],
* ],
* dirList: ['src/**\/*.vue'],
* },
* ]);
* // 同 dirList 的规则会被合并,避免重复读写
* ```
*/
function batchReplaceFileContent(replaceList) {
// 按 dirList 分组,将相同 dirList 的规则合并
var groupMap = new Map();
var _iterator7 = _createForOfIteratorHelper(replaceList),
_step7;
try {
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
var _groupMap$get$rules;
var item = _step7.value;
var dirList = item.dirList,
list = item.list;
if (!(list === null || list === void 0 ? void 0 : list.length)) continue;
var newDir = Array.isArray(dirList) ? dirList : [dirList];
var dirKey = JSON.stringify(newDir.sort());
if (!groupMap.has(dirKey)) {
groupMap.set(dirKey, {
dirList: newDir,
rules: []
});
}
(_groupMap$get$rules = groupMap.get(dirKey).rules).push.apply(_groupMap$get$rules, _toConsumableArray(list));
}
} catch (err) {
_iterator7.e(err);
} finally {
_iterator7.f();
}
var glob = getGlob();
var _iterator8 = _createForOfIteratorHelper(groupMap),
_step8;
try {
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
var _step8$value = _slicedToArray(_step8.value, 2),
_step8$value$ = _step8$value[1],
_dirList = _step8$value$.dirList,
rules = _step8$value$.rules;
var files = _toConsumableArray(new Set(_dirList.flatMap(function (pattern) {
return glob.sync(pattern);
})));
var _iterator9 = _createForOfIteratorHelper(files),
_step9;
try {
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
var file = _step9.value;
if (fs__default.statSync(file).isDirectory()) continue;
var content = fs__default.readFileSync(file, 'utf-8');
var changed = false;
var _iterator0 = _createForOfIteratorHelper(rules),
_step0;
try {
for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
var _step0$value = _slicedToArray(_step0.value, 2),
from = _step0$value[0],
to = _step0$value[1];
var newContent = typeof from === 'string' ? content.replaceAll(from, to) : content.replace(from, to);
if (newContent !== content) {
content = newContent;
changed = true;
}
}
} catch (err) {
_iterator0.e(err);
} finally {
_iterator0.f();
}
if (changed) {
fs__default.writeFileSync(file, content);
console.log("[batchReplaceFileContent]: \u6587\u4EF6: ".concat(file));
}
}
} catch (err) {
_iterator9.e(err);
} finally {
_iterator9.f();
}
}
} catch (err) {
_iterator8.e(err);
} finally {
_iterator8.f();
}
}
/**
* 批量重命名文件和文件夹(同步版本)
* @param {string} dirPath - 要处理的目录路径
* @param {Object} renameConfig - 重命名配置对象 { 旧名称: 新名称 }
* @param {boolean} [recursive=true] - 是否递归处理子目录
* @example
* ```ts
* batchRenameDirEntries('src/components', {
* 'press-icon-plus': 'press-icon',
* 'press-dialog-plus': 'press-dialog',
* });
* // 递归将 src/components 下名为 press-icon-plus、press-dialog-plus 的文件/文件夹重命名
*
* // 只重命名当前层、不递归
* batchRenameDirEntries('src/components', { 'a': 'b' }, false);
* ```
*/
function batchRenameDirEntries(dirPath, renameConfig) {
var recursive = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
try {
var items = fs__default.readdirSync(dirPath, {
withFileTypes: true
});
var _iterator1 = _createForOfIteratorHelper(items),
_step1;
try {
for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
var item = _step1.value;
var oldPath = path__default.join(dirPath, item.name);
var newName = item.name;
var _loop = function _loop() {
var _Object$entries$_i = _slicedToArray(_Object$entries[_i2], 2),
oldName = _Object$entries$_i[0],
newNamePart = _Object$entries$_i[1];
var oldNameReg = new RegExp("^".concat(oldName, "(\\.\\w+)$"));
if (item.name === oldName) {
newName = newNamePart;
return 0; // break
} else if (oldNameReg.test(item.name)) {
newName = item.name.replace(oldNameReg, function (_, postfix) {
return newNamePart + postfix;
});
return 0; // break
}
},
_ret;
for (var _i2 = 0, _Object$entries = Object.entries(renameConfig); _i2 < _Object$entries.length; _i2++) {
_ret = _loop();
if (_ret === 0) break;
}
if (newName !== item.name) {
var newPath = path__default.join(dirPath, newName);
console.log("[batchRenameDirEntries]: ".concat(oldPath, " -> ").concat(newPath));
fs__default.renameSync(oldPath, newPath);
}
if (recursive && item.isDirectory()) {
var currentPath = newName !== item.name ? path__default.join(dirPath, newName) : oldPath;
batchRenameDirEntries(currentPath, renameConfig, recursive);
}
}
} catch (err) {
_iterator1.e(err);
} finally {
_iterator1.f();
}
} catch (error) {
console.error("[batchRenameDirEntries] Error processing directory ".concat(dirPath, ":"), error);
}
}
export { batchRenameDirEntries, batchReplaceFileContent, getComponentContentReplaceRules, getComponentPascalReg, getMetaConfigPascalReplaceRules, getThreeStageRenameConfig };