Initial commit: Re-connected to Gitea

This commit is contained in:
2026-03-22 04:39:45 +08:00
commit 8e76dd7a7b
103 changed files with 7132 additions and 0 deletions

View File

@@ -0,0 +1,157 @@
// scripts/generate-index-use.ts
import { writeFileSync, readFileSync } from "fs";
import { extname, relative, resolve, basename } from "path";
import { globSync } from "glob";
interface Config {
targetDirs: string[];
includeExtensions: string[];
importSyntax: "@import";
importSyntaxTail?: string;
excludeFilePattern: RegExp[];
excludeDirs: string[];
warnDuplicateTailwindImport: boolean;
indexFileName: string;
}
// 配置项
const srcDirConfig: Config = {
targetDirs: ["src"], // 包含的文件夹
includeExtensions: [".css"], // 目标文件后缀
importSyntax: "@import", // 导入时使用的语法
excludeFilePattern: [/index\.css/, /index\.scss/, /\.(test|spec)\./], // 正则若匹配则排除
// 排除的文件夹
excludeDirs: [
"__tests__",
"tests",
"story",
"stories",
"types",
"node_modules",
"dist",
"build",
],
warnDuplicateTailwindImport: true,
indexFileName: "index.css", // 生成的入口文件名称
};
// ======================================================================
/**
* 判断是否是有效 CSS 文件
* @param filePath 文件绝对路径
* @returns 是否为有效文件
*/
function isValidFile(filePath: string, config: Config): boolean {
// 过滤排除的文件
const filenameWithExt = filePath.split(/[\\/]/).pop()!; // “\\” 匹配反斜杠 “\”,“/” 匹配正斜杠 “/”pop 返回最后一个 “/” 后面的内容
const shouldExcludeFile = config.excludeFilePattern.some((pattern) =>
pattern.test(filenameWithExt),
);
if (shouldExcludeFile) {
return false; // 如果匹配到排除规则,跳过当前文件
}
// 过滤排除的文件夹
const normalizedFilePath = filePath.replace(/\\/g, "/"); // “\\” 匹配反斜杠 “\”,“/” 匹配正斜杠 “/”
const shouldExcludeDir = config.excludeDirs.some(
(dir) => normalizedFilePath.includes(`/${dir}/`), // 前后都有“/” 是为了避免误匹配到文件名(如 test.js 不会被排除)
);
if (shouldExcludeDir) return false; // 如果匹配到排除规则,跳过当前文件
// 过滤非目标扩展名,只有指定的才通过
const ext = extname(filePath);
const isValidExt = config.includeExtensions.includes(ext);
if (!isValidExt) {
return false; // 如果不是指定扩展名,跳过当前文件
}
// @import "tailwindcss" 重复警告,生成的入口文件会自动加一条,其他文件无需重复导入
if (config.warnDuplicateTailwindImport) {
try {
const fileContent = readFileSync(filePath, "utf-8");
if (
fileContent.includes('@import "tailwindcss"') ||
fileContent.includes("@import 'tailwindcss'")
) {
console.warn(
`${filePath} 中含有重复的 @import "tailwindcss" 导入,应手动删除`,
);
}
} catch (e) {
const errorMsg = e instanceof Error ? e.message : String(e);
console.warn(`⚠️ 读取文件内容失败(跳过过滤): ${filePath}`, errorMsg);
}
}
return true;
}
// ======================================================================
/**
* 生成 “@import” 导入语句
*/
function generateIndexFile(config: Config) {
const [targetDir] = config.targetDirs;
const dirPath = resolve(process.cwd(), targetDir); //目标文件夹绝对路径, 通常是 /project/src
const searchPattern = resolve(dirPath, "**", "*.*"); // 搜索路径 “dirPath/**/*”
const allFiles = globSync(searchPattern, {
nodir: true, // 不匹配文件夹,只匹配文件
absolute: true, // 返回从根目录开始的绝对路径
windowsPathsNoEscape: true, // 禁用 Windows 路径的反斜杠转义
dot: false, // 不配隐藏文件或目录(以 . 开头的文件)
follow: true, // 跟踪符号链接symlinks继续解析并返回链接的目标文件或目录
});
const validFiles = allFiles.filter((value) => isValidFile(value, config)); // 过滤出要导入的有效 CSS 文件
console.log(`✅ 有效 CSS 文件数量: ${validFiles.length}`);
validFiles.sort(); // 排序
const importStatements = validFiles.map((file) => {
const relPath = relative(dirPath, file); // 算出 src 与 css文件 的相对路径
let importPath = "./" + relPath.replace(/\\/g, "/"); // 给相对路径前面加上 “./”,并将 “\\” 替换成 “/”
// 拼接 @import 语句
if (config.importSyntaxTail !== undefined) {
return `${config.importSyntax} '${importPath}' ${config.importSyntaxTail};`;
} else {
return `${config.importSyntax} '${importPath}';`;
}
});
// index.css 文件的顶部内容
const indexContent = `
@import "tailwindcss";
${importStatements.join("\n")}
`.trim(); // 使用 trim 移除开头多余的换行
const indexFilePath = resolve(dirPath, config.indexFileName);
// 创建和写入 index.css 文件
writeFileSync(indexFilePath, indexContent, "utf-8");
console.log(`✅ 成功生成 ${config.indexFileName}: ${indexFilePath}`);
}
// ======================================================================
/**
* 主函数
*/
function main() {
try {
generateIndexFile(srcDirConfig);
} catch (e) {
const errorMsg = e instanceof Error ? e.message : String(e);
console.error(
`❌ 文件夹 ${srcDirConfig.targetDirs} 扫描和生成 ${srcDirConfig.indexFileName} 失败:`,
errorMsg,
);
process.exit(1);
}
}
main();