fix: 修复通配符匹配问题

This commit is contained in:
ren
2025-10-14 15:07:44 +08:00
parent 7f864dbb36
commit 811d37052b
2 changed files with 281 additions and 143 deletions

149
index.js
View File

@@ -3,6 +3,31 @@ const fsSync = require('fs');
const path = require('path');
const crypto = require('crypto');
/**
* 工具函数:安全执行异步操作,忽略错误
*
* @template T
* @param {() => Promise<T>} fn - 要执行的异步函数
* @param {T} defaultValue - 出错时的默认值
* @returns {Promise<T>} 函数执行结果或默认值
*/
async function safeExecute(fn, defaultValue = undefined) {
try {
return await fn();
} catch (error) {
return defaultValue;
}
}
/**
* 工具函数:安全执行同步操作,忽略错误
*
* @template T
* @param {() => T} fn - 要执行的同步函数
* @param {T} defaultValue - 出错时的默认值
* @returns {T} 函数执行结果或默认值
*/
/**
* 错误类型常量.
*
@@ -191,8 +216,10 @@ class FileDiscovery {
const files = new Set();
for (const pattern of patterns) {
const matchedFiles = await this.expandGlob(pattern.trim());
matchedFiles.forEach(file => files.add(file));
await safeExecute(async () => {
const matchedFiles = await this.expandGlob(pattern.trim());
matchedFiles.forEach(file => files.add(file));
});
}
return Array.from(files).sort();
@@ -240,17 +267,16 @@ class FileDiscovery {
async expandGlob(pattern) {
// 如果是普通文件路径,直接返回
if (!pattern.includes('*') && !pattern.includes('?')) {
try {
const stats = await fs.stat(pattern);
const stats = await safeExecute(() => fs.stat(pattern));
if (stats) {
if (stats.isFile()) {
return [pattern];
} else if (stats.isDirectory()) {
// 如果是目录,返回目录下所有文件
return await this.getAllFilesInDirectory(pattern);
}
} catch (error) {
return [];
}
return [];
}
// 处理 glob 模式
@@ -267,26 +293,22 @@ class FileDiscovery {
async getAllFilesInDirectory(dirPath, includeHidden = false) {
const files = [];
try {
const entries = await fs.readdir(dirPath, { withFileTypes: true });
const entries = await safeExecute(() => fs.readdir(dirPath, { withFileTypes: true }), []);
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
// 默认忽略隐藏文件(以.开头的文件和目录)
if (!includeHidden && entry.name.startsWith('.')) {
continue;
}
if (entry.isFile()) {
files.push(fullPath);
} else if (entry.isDirectory()) {
const subFiles = await this.getAllFilesInDirectory(fullPath, includeHidden);
files.push(...subFiles);
}
// 默认忽略隐藏文件(以.开头的文件和目录)
if (!includeHidden && entry.name.startsWith('.')) {
continue;
}
if (entry.isFile()) {
files.push(fullPath);
} else if (entry.isDirectory()) {
const subFiles = await this.getAllFilesInDirectory(fullPath, includeHidden);
files.push(...subFiles);
}
} catch (error) {
// 忽略无法访问的目录
}
return files;
@@ -312,21 +334,17 @@ class FileDiscovery {
}
// 处理简单的文件名通配符
try {
const entries = await fs.readdir(dir, { withFileTypes: true });
const entries = await safeExecute(() => fs.readdir(dir, { withFileTypes: true }), []);
for (const entry of entries) {
// 默认忽略隐藏文件(以.开头的文件)
if (entry.name.startsWith('.')) {
continue;
}
if (entry.isFile() && this.matchPattern(entry.name, filename)) {
files.push(path.join(dir, entry.name));
}
for (const entry of entries) {
// 默认忽略隐藏文件(以.开头的文件)
if (entry.name.startsWith('.')) {
continue;
}
if (entry.isFile() && this.matchPattern(entry.name, filename)) {
files.push(path.join(dir, entry.name));
}
} catch (error) {
// 目录不存在或无法访问
}
return files;
@@ -348,17 +366,17 @@ class FileDiscovery {
const basePath = parts[0].replace(/\*+$/, '').replace(/\/$/, '') || '.';
const remainingPattern = parts[1].replace(/^\//, '');
try {
const allFiles = await this.getAllFilesInDirectory(basePath);
const allFiles = await safeExecute(() => this.getAllFilesInDirectory(basePath), []);
for (const file of allFiles) {
const relativePath = path.relative(basePath, file);
if (this.matchPattern(relativePath, remainingPattern)) {
files.push(file);
}
for (const file of allFiles) {
const relativePath = path.relative(basePath, file);
// 对于 **/pattern 模式,匹配相对路径的末尾部分
if (remainingPattern && (relativePath === remainingPattern || relativePath.endsWith('/' + remainingPattern))) {
files.push(file);
} else if (this.matchPattern(relativePath, remainingPattern)) {
// 对于包含通配符的模式,使用 matchPattern
files.push(file);
}
} catch (error) {
// 忽略错误
}
} else {
// 处理单层通配符
@@ -385,34 +403,30 @@ class FileDiscovery {
const [currentPart, ...remainingParts] = parts;
const files = [];
try {
const entries = await fs.readdir(currentPath, { withFileTypes: true });
const entries = await safeExecute(() => fs.readdir(currentPath, { withFileTypes: true }), []);
for (const entry of entries) {
// 默认忽略隐藏文件和目录(以.开头的)
if (entry.name.startsWith('.')) {
continue;
}
for (const entry of entries) {
// 默认忽略隐藏文件和目录(以.开头的)
if (entry.name.startsWith('.')) {
continue;
}
const fullPath = path.join(currentPath, entry.name);
const fullPath = path.join(currentPath, entry.name);
if (this.matchPattern(entry.name, currentPart)) {
if (remainingParts.length === 0) {
// 最后一部分,检查是否为文件
if (entry.isFile()) {
files.push(fullPath);
}
} else {
// 还有更多部分,递归处理
if (entry.isDirectory()) {
const subFiles = await this.matchPatternParts(remainingParts, fullPath);
files.push(...subFiles);
}
if (this.matchPattern(entry.name, currentPart)) {
if (remainingParts.length === 0) {
// 最后一部分,检查是否为文件
if (entry.isFile()) {
files.push(fullPath);
}
} else {
// 还有更多部分,递归处理
if (entry.isDirectory()) {
const subFiles = await this.matchPatternParts(remainingParts, fullPath);
files.push(...subFiles);
}
}
}
} catch (error) {
// 忽略错误
}
return files;
@@ -686,4 +700,5 @@ module.exports = {
ActionOutputs,
ActionError,
ErrorType,
safeExecute,
};