chore: remove all cn comments (#277)

This commit is contained in:
tecvan
2025-07-30 14:52:35 +08:00
committed by GitHub
parent 875e97a40d
commit f93f26fc48
26 changed files with 5109 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
/**
* 中文字符的Unicode范围正则表达式
*/
const CHINESE_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/;
const CHINESE_EXTRACT_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3000-\u303f\uff00-\uffef]+/g;
/**
* 检测文本是否包含中文字符
*/
export const containsChinese = (text: string): boolean => {
return CHINESE_REGEX.test(text);
};
/**
* 提取文本中的中文部分
*/
export const extractChineseParts = (text: string): string[] => {
return text.match(CHINESE_EXTRACT_REGEX) || [];
};
/**
* 计算文本中中文字符的数量
*/
export const countChineseCharacters = (text: string): number => {
const matches = text.match(CHINESE_EXTRACT_REGEX);
if (!matches) return 0;
return matches.reduce((count, match) => count + match.length, 0);
};
/**
* 检测文本是否主要由中文组成
*/
export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boolean => {
const totalLength = text.length;
if (totalLength === 0) return false;
const chineseLength = countChineseCharacters(text);
return chineseLength / totalLength >= threshold;
};
/**
* 清理注释文本,移除注释符号和多余空格
*/
export const cleanCommentText = (
text: string,
commentType: 'single-line' | 'multi-line',
language?: string
): string => {
let cleaned = text;
if (commentType === 'single-line') {
// 根据语言类型移除不同的单行注释符号
switch (language) {
case 'yaml':
case 'toml':
case 'shell':
case 'python':
case 'ruby':
cleaned = cleaned.replace(/^#\s*/, '');
break;
case 'ini':
cleaned = cleaned.replace(/^[;#]\s*/, '');
break;
case 'php':
cleaned = cleaned.replace(/^(?:\/\/|#)\s*/, '');
break;
default:
// JavaScript/TypeScript/Go/Java/C/C++/C# style
cleaned = cleaned.replace(/^\/\/\s*/, '');
}
} else if (commentType === 'multi-line') {
// 根据语言类型移除不同的多行注释符号
switch (language) {
case 'html':
case 'xml':
case 'markdown':
cleaned = cleaned.replace(/^<!--\s*/, '').replace(/\s*-->$/, '');
break;
case 'python':
cleaned = cleaned.replace(/^"""\s*/, '').replace(/\s*"""$/, '');
break;
case 'ruby':
cleaned = cleaned.replace(/^=begin\s*/, '').replace(/\s*=end$/, '');
break;
default:
// JavaScript/TypeScript/Go/Java/C/C++/C#/CSS style
cleaned = cleaned.replace(/^\/\*\s*/, '').replace(/\s*\*\/$/, '');
// 移除每行开头的 * 符号
cleaned = cleaned.replace(/^\s*\*\s?/gm, '');
}
}
// 移除多余的空格和换行
cleaned = cleaned.trim();
return cleaned;
};
/**
* 验证翻译结果是否有效
*/
export const isValidTranslation = (original: string, translated: string): boolean => {
// 基本验证
if (!translated || translated.trim().length === 0) {
return false;
}
// 检查是否还包含中文(可能翻译失败)
if (containsChinese(translated)) {
return false;
}
// 检查长度是否合理(翻译后的文本不应该比原文长太多)
if (translated.length > original.length * 3) {
return false;
}
return true;
};

View File

@@ -0,0 +1,173 @@
import { Result } from '../types/index';
/**
* 函数组合 - 从左到右执行
*/
export const pipe =
<T>(...fns: Function[]) =>
(value: T) =>
fns.reduce((acc, fn) => fn(acc), value);
/**
* 函数组合 - 从右到左执行
*/
export const compose =
<T>(...fns: Function[]) =>
(value: T) =>
fns.reduceRight((acc, fn) => fn(acc), value);
/**
* 柯里化函数
*/
export const curry =
(fn: Function) =>
(...args: any[]) =>
args.length >= fn.length
? fn(...args)
: (...more: any[]) => curry(fn)(...args, ...more);
/**
* 异步映射
*/
export const asyncMap = curry(
async <T, U>(fn: (item: T) => Promise<U>, items: T[]): Promise<U[]> =>
Promise.all(items.map(fn)),
);
/**
* 异步过滤
*/
export const asyncFilter = curry(
async <T>(
predicate: (item: T) => Promise<boolean>,
items: T[],
): Promise<T[]> => {
const results = await Promise.all(items.map(predicate));
return items.filter((_, index) => results[index]);
},
);
/**
* 异步归约
*/
export const asyncReduce = curry(
async <T, U>(
fn: (acc: U, item: T) => Promise<U>,
initial: U,
items: T[],
): Promise<U> => {
let result = initial;
for (const item of items) {
result = await fn(result, item);
}
return result;
},
);
/**
* 创建成功结果
*/
export const success = <T>(data: T): Result<T> => ({ success: true, data });
/**
* 创建失败结果
*/
export const failure = <E>(error: E): Result<never, E> => ({
success: false,
error,
});
/**
* 安全的异步操作包装
*/
export const tryCatch = async <T>(fn: () => Promise<T>): Promise<Result<T>> => {
try {
const data = await fn();
return success(data);
} catch (error) {
return failure(error instanceof Error ? error : new Error(String(error)));
}
};
/**
* 同步版本的安全操作包装
*/
export const tryCatchSync = <T>(fn: () => T): Result<T> => {
try {
const data = fn();
return success(data);
} catch (error) {
return failure(error instanceof Error ? error : new Error(String(error)));
}
};
/**
* 数组分块
*/
export const chunk = <T>(array: T[], size: number): T[][] => {
const chunks: T[][] = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
};
/**
* 延迟执行
*/
export const delay = (ms: number): Promise<void> =>
new Promise(resolve => setTimeout(resolve, ms));
/**
* 重试机制
*/
export const retry = async <T>(
fn: () => Promise<T>,
maxAttempts: number = 3,
delayMs: number = 1000,
): Promise<T> => {
let lastError: Error;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
if (attempt < maxAttempts) {
await delay(delayMs * attempt); // 指数退避
}
}
}
throw lastError!;
};
/**
* 深度合并对象
*/
export const deepMerge = <T extends Record<string, any>>(
target: T,
source: Partial<T>,
): T => {
const result = { ...target } as T;
for (const key in source) {
if (source[key] !== undefined) {
if (
typeof source[key] === 'object' &&
source[key] !== null &&
!Array.isArray(source[key]) &&
typeof target[key] === 'object' &&
target[key] !== null &&
!Array.isArray(target[key])
) {
(result as any)[key] = deepMerge(target[key], source[key]!);
} else {
(result as any)[key] = source[key]!;
}
}
}
return result;
};

View File

@@ -0,0 +1,94 @@
import { simpleGit } from 'simple-git';
import * as path from 'path';
import { tryCatch } from './fp';
import { Result } from '../types/index';
/**
* 获取Git仓库中的所有已跟踪文件
*/
export const getGitTrackedFiles = async (
root: string,
): Promise<Result<string[]>> => {
return tryCatch(async () => {
const git = simpleGit(root);
const files = await git.raw(['ls-files']);
return files
.split('\n')
.filter(Boolean)
.map(file => path.resolve(root, file));
});
};
/**
* 获取Git仓库中的所有文件包括未跟踪的
*/
export const getAllGitFiles = async (
root: string,
): Promise<Result<string[]>> => {
return tryCatch(async () => {
const git = simpleGit(root);
// 获取已跟踪的文件
const trackedFiles = await git.raw(['ls-files']);
const trackedFilesArray = trackedFiles
.split('\n')
.filter(Boolean)
.map(file => path.resolve(root, file));
// 获取未跟踪的文件
const status = await git.status();
const untrackedFiles = status.not_added.map(file =>
path.resolve(root, file),
);
// 合并并去重
const allFiles = [...new Set([...trackedFilesArray, ...untrackedFiles])];
return allFiles;
});
};
/**
* 检查目录是否是Git仓库
*/
export const isGitRepository = async (
root: string,
): Promise<Result<boolean>> => {
return tryCatch(async () => {
const git = simpleGit(root);
await git.status();
return true;
});
};
/**
* 获取Git仓库的根目录
*/
export const getGitRoot = async (cwd: string): Promise<Result<string>> => {
return tryCatch(async () => {
const git = simpleGit(cwd);
const root = await git.revparse(['--show-toplevel']);
return root.trim();
});
};
/**
* 检查文件是否被Git忽略
*/
export const isIgnoredByGit = async (
root: string,
filePath: string,
): Promise<Result<boolean>> => {
return tryCatch(async () => {
const git = simpleGit(root);
const relativePath = path.relative(root, filePath);
try {
await git.raw(['check-ignore', relativePath]);
return true; // 文件被忽略
} catch {
return false; // 文件未被忽略
}
});
};

View File

@@ -0,0 +1,227 @@
import { SourceFileLanguage, CommentPattern } from '../types/index';
/**
* 根据文件扩展名识别编程语言
*/
export const detectLanguage = (filePath: string): SourceFileLanguage => {
const ext = filePath.toLowerCase().split('.').pop();
const languageMap: Record<string, SourceFileLanguage> = {
'ts': 'typescript',
'tsx': 'typescript',
'js': 'javascript',
'jsx': 'javascript',
'go': 'go',
'md': 'markdown',
'txt': 'text',
'json': 'json',
'yaml': 'yaml',
'yml': 'yaml',
'toml': 'toml',
'ini': 'ini',
'conf': 'ini',
'config': 'ini',
'sh': 'shell',
'bash': 'shell',
'zsh': 'shell',
'fish': 'shell',
'py': 'python',
'css': 'css',
'scss': 'css',
'sass': 'css',
'less': 'css',
'html': 'html',
'htm': 'html',
'xml': 'xml',
'php': 'php',
'rb': 'ruby',
'rs': 'rust',
'java': 'java',
'c': 'c',
'h': 'c',
'cpp': 'cpp',
'cxx': 'cpp',
'cc': 'cpp',
'hpp': 'cpp',
'cs': 'csharp'
};
return languageMap[ext || ''] || 'other';
};
/**
* 根据文件扩展名过滤文件
*/
export const filterFilesByExtensions = (
files: string[],
extensions: string[]
): string[] => {
if (extensions.length === 0) {
// 默认支持的文本文件扩展名
const defaultExtensions = [
'.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json',
'.yaml', '.yml', '.toml', '.ini', '.conf', '.config',
'.sh', '.bash', '.zsh', '.fish', '.py', '.css', '.scss', '.sass', '.less',
'.html', '.htm', '.xml', '.php', '.rb', '.rs', '.java', '.c', '.h',
'.cpp', '.cxx', '.cc', '.hpp', '.cs'
];
return files.filter(file =>
defaultExtensions.some(ext => file.toLowerCase().endsWith(ext))
);
}
return files.filter(file => {
const lowerFile = file.toLowerCase();
return extensions.some(ext => {
const lowerExt = ext.toLowerCase();
// 如果扩展名已经有点号,直接使用;否则添加点号
const extWithDot = lowerExt.startsWith('.') ? lowerExt : `.${lowerExt}`;
return lowerFile.endsWith(extWithDot);
});
});
};
/**
* 获取不同编程语言的注释模式
*/
export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern | null => {
const commentPatterns: Record<SourceFileLanguage, CommentPattern> = {
typescript: {
single: /(?:^|[^:])\s*\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
javascript: {
single: /(?:^|[^:])\s*\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
go: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
markdown: {
single: /<!--(.*)-->/g,
multiStart: /<!--/g,
multiEnd: /-->/g
},
text: {
single: /^(.*)$/gm, // 文本文件每行都可能是注释
multiStart: /^/g,
multiEnd: /$/g
},
json: {
single: /\/\/(.*)$/gm, // JSON通常不支持注释但一些工具支持
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
yaml: {
single: /#(.*)$/gm,
multiStart: /^$/g, // YAML不支持多行注释
multiEnd: /^$/g
},
toml: {
single: /#(.*)$/gm,
multiStart: /^$/g, // TOML不支持多行注释
multiEnd: /^$/g
},
ini: {
single: /[;#](.*)$/gm, // INI文件支持 ; 和 # 作为注释
multiStart: /^$/g, // INI不支持多行注释
multiEnd: /^$/g
},
shell: {
single: /#(.*)$/gm,
multiStart: /^$/g, // Shell脚本不支持多行注释
multiEnd: /^$/g
},
python: {
single: /#(.*)$/gm,
multiStart: /"""[\s\S]*?$/gm, // Python docstring
multiEnd: /[\s\S]*?"""/gm
},
css: {
single: /^$/g, // CSS不支持单行注释
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
html: {
single: /^$/g, // HTML不支持单行注释
multiStart: /<!--/g,
multiEnd: /-->/g
},
xml: {
single: /^$/g, // XML不支持单行注释
multiStart: /<!--/g,
multiEnd: /-->/g
},
php: {
single: /(?:\/\/|#)(.*)$/gm, // PHP支持 // 和 # 作为单行注释
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
ruby: {
single: /#(.*)$/gm,
multiStart: /=begin/g,
multiEnd: /=end/g
},
rust: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
java: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
c: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
cpp: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
csharp: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
},
other: {
single: /\/\/(.*)$/gm,
multiStart: /\/\*/g,
multiEnd: /\*\//g
}
};
return commentPatterns[language] || null;
};
/**
* 检查文件是否支持处理
*/
export const isSupportedFile = (filePath: string): boolean => {
const language = detectLanguage(filePath);
return language !== 'other';
};
/**
* 获取文件的MIME类型用于判断是否为文本文件
*/
export const isTextFile = (filePath: string): boolean => {
const textExtensions = [
'.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json',
'.css', '.scss', '.sass', '.less', '.html', '.htm', '.xml',
'.yaml', '.yml', '.toml', '.ini', '.conf', '.config',
'.sh', '.bash', '.zsh', '.fish', '.py', '.java', '.c', '.cpp', '.h', '.hpp', '.cs',
'.php', '.rb', '.rs', '.kt', '.swift', '.dart', '.scala'
];
return textExtensions.some(ext =>
filePath.toLowerCase().endsWith(ext)
);
};

View File

@@ -0,0 +1,51 @@
/**
* 信号量并发控制类
*/
export class Semaphore {
private permits: number;
private waiting: (() => void)[] = [];
constructor(permits: number) {
this.permits = permits;
}
/**
* 获取许可
*/
async acquire(): Promise<void> {
if (this.permits > 0) {
this.permits--;
return;
}
return new Promise(resolve => {
this.waiting.push(resolve);
});
}
/**
* 释放许可
*/
release(): void {
this.permits++;
const next = this.waiting.shift();
if (next) {
this.permits--;
next();
}
}
/**
* 获取当前可用许可数
*/
available(): number {
return this.permits;
}
/**
* 获取等待队列长度
*/
waitingCount(): number {
return this.waiting.length;
}
}