@quick-game/cli
Version:
Command line interface for rapid qg development
201 lines (192 loc) • 6.05 kB
JavaScript
; /**
* author:
* time:
* describtion: fs适配层
*/
const { warn } = require('../../cli-shared-utils');
const fs = require('fs');
const $path = require('path');
// path <string> | <Buffer> | <URL>
// options <Object>
// recursive <boolean> 如果为 true,则执行递归的目录删除。在递归模式中,如果 path 不存在则不报告错误,并且在失败时重试操作。默认值: false。
// exclude <Regexp> 符合该正则的就不删除
// 在文件(而不是目录)上使用 fs.rmdirSync() 会导致在 Windows 上出现 ENOENT 错误、在 POSIX 上出现 ENOTDIR 错误。
// 稳定性 - 递归的删除是实验性的(因此不在生产环境中使用原来的参数,2而采用更兼容的方式)
const rmdirSync = (path, options) => {
if (options && options.recursive) {
let files = [];
if (fs.existsSync(path)) {
if (fs.statSync(path).isDirectory()) {
files = fs.readdirSync(path);
for (const file of files) {
const currentPath = $path.join(path, file);
if (fs.statSync(currentPath).isDirectory()) {
rmdirSync(currentPath, options);
} else {
fs.unlinkSync(currentPath);
}
}
}
}
}
return fs.rmdirSync(path);
};
// 拓展
// 将指定路径上的文件内容解析为json对象
const parse = (path) => {
const json = fs.readFileSync(path);
return JSON.parse(json) || {};
};
// 依赖 rmdirSync
const clearDir = (path, options) => {
if (fs.existsSync(path)) {
let files = [];
if (fs.existsSync(path)) {
files = fs.readdirSync(path);
for (const file of files) {
const currentPath = $path.join(path, file);
if (options && options.exclude && options.exclude.test(currentPath)) {
console.log(`不删除${currentPath}`);
continue;
}
if (fs.statSync(currentPath).isDirectory()) {
clearDir(currentPath, options);
let currentFiles = [];
currentFiles = fs.readdirSync(currentPath);
if (!currentFiles.length) {
fs.rmdirSync(currentPath);
}
} else {
fs.unlinkSync(currentPath);
}
}
}
} else {
if (options && options.build) {
console.log(`创建目录${path}`);
fs.mkdirSync(path);
}
}
};
const overwrite = (src, dest, options) => {
if (options) {
options.basePath = $path.normalize(src);
}
overwriteFile(src, dest, options);
};
// 覆盖指定的文件或者文件夹中同名的文件和文件夹(不会删除dest中存在但是src中不存在的文件和文件夹)
const overwriteFile = (src, dest, options) => {
if (!fs.existsSync(src)) {
console.log(`不存在${src}`);
return;
}
if (options && options.exclude) {
const relativePath = $path.relative(options.basePath, $path.normalize(src));
if (options.basePath !== $path.normalize(src) && options.exclude.test(relativePath)) {
console.log(`${src}-x->${dest}`);
return;
}
}
if (fs.statSync(src).isDirectory()) {
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest);
}
let files = [];
files = fs.readdirSync(src);
for (const file of files) {
if (options && options.exclude && options.exclude.test(file)) {
continue;
}
overwriteFile($path.join(src, file), $path.join(dest, file), options);
}
} else {
const directory = $path.dirname(dest);
fs.mkdirSync(directory, { recursive: true });
// 默认情况下,如果 dest 已经存在,则覆盖它。
fs.copyFileSync(src, dest);
}
return true;
};
/**
* 遍历目录文件 同步方法
* @param dir
* @param files 收集的文件列表
*/
const traverseDirSync = function (dir, files, options) {
const st = fs.statSync(dir);
if (st && st.isFile()) {
files.push(dir);
return;
}
const list = fs.readdirSync(dir);
list.forEach(function (file) {
const isExclude = options && options.exclude && options.exclude.test(file);
if (!isExclude) {
file = $path.join(dir, file);
const stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
traverseDirSync(file, files, options);
} else {
if (options && options.include) {
if (options.include.test(file)) {
files.push(file);
}
return;
}
files.push(file);
}
}
});
};
/**
* 替换文件夹中文件的字符串
* @param {*} dir 文件夹
* @param {*} options {include: 需要替换的文件, exclude: 需要排除的文件或文件夹,map: 需要替换的字符串, to:需要替换成该字符串}
* options: replaceFrom:map找到字符串,其中需要被替换的字符串,replaceTo:其中需要替换成的字符串
* @returns
*/
const replaceFiles = (dir, options) => {
if (!fs.existsSync(dir)) {
console.log(`不存在${dir}`);
return;
}
if (!options || !options.map) {
console.log(`options或map、to为空,${options}`);
return;
}
const files = [];
traverseDirSync(dir, files, options);
// console.log(files)
for (const file of files) {
let content = fs.readFileSync(file, {
encoding: 'utf-8'
});
const regexp = new RegExp(options.map, 'g');
if (content && options.map.test(content)) {
if (options.replaceFrom && options.replaceTo) {
warn(`>>>> ${file} replaceTo ${options.replaceTo}`);
var match;
while ((match = regexp.exec(content)) !== null) {
var replaceStr = match[0].replace(options.replaceFrom, options.replaceTo);
content = content.replace(match[0], replaceStr);
}
fs.writeFileSync(file, content);
} else if (options.to) {
warn(`>>>> ${file} replaceTo ${options.to}`);
content = content.replace(regexp, options.to);
fs.writeFileSync(file, content);
}
}
}
return true;
};
const fsExt = {
clearDir,
parse,
overwrite
};
module.exports = {
rmdirSync,
replaceFiles,
fsExt
};