148 lines
4.4 KiB
TypeScript
148 lines
4.4 KiB
TypeScript
import fs from "fs";
|
||
import path from "path";
|
||
// 1. 引入 tinyglobby
|
||
import { globSync } from "tinyglobby";
|
||
|
||
interface Config {
|
||
outputDir: string;
|
||
outputFilenameWithExt: string;
|
||
scanDirs: string[];
|
||
importPrefix: string;
|
||
predefineStatements: string[];
|
||
includeExtensions: string[];
|
||
excludeDirs: string[];
|
||
excludeFileExtensions: string[];
|
||
excludePatterns: RegExp[];
|
||
}
|
||
|
||
const cssConfig: Config = {
|
||
outputDir: "src",
|
||
outputFilenameWithExt: "index.css",
|
||
scanDirs: ["src"],
|
||
importPrefix: "@import",
|
||
predefineStatements: [],
|
||
includeExtensions: [".css"],
|
||
excludeDirs: ["__tests__", "tests", "story", "stories", "types"],
|
||
excludeFileExtensions: [],
|
||
excludePatterns: [/^index\.(css)$/, /\.(test|spec)\./, /\.(story|stories)\./],
|
||
};
|
||
|
||
const tsConfig: Config = {
|
||
outputDir: "src",
|
||
outputFilenameWithExt: "index.ts",
|
||
scanDirs: ["src"],
|
||
importPrefix: "export * from",
|
||
predefineStatements: ["import './index.css'"],
|
||
includeExtensions: [".ts", "tsx", "js", "jsx"],
|
||
excludeDirs: ["__tests__", "tests", "story", "stories", "types"],
|
||
excludeFileExtensions: [".d.ts"],
|
||
excludePatterns: [
|
||
/^index\.(ts|tsx|js|jsx)$/,
|
||
/\.(test|spec)\./,
|
||
/\.(story|stories)\./,
|
||
],
|
||
};
|
||
|
||
const normalizePath = (p: string) => p.replace(/\\/g, "/");
|
||
|
||
const isExcludeDir = (filePath: string, excludeDirs: string[]) => {
|
||
const normalized = normalizePath(filePath);
|
||
return excludeDirs.some((dir) => normalized.includes(`/${dir}/`));
|
||
};
|
||
|
||
const isExcludeFileExtensions = (
|
||
filePath: string,
|
||
excludeFileExtensions: string[],
|
||
) => excludeFileExtensions.some((ext) => filePath.endsWith(ext));
|
||
|
||
const isExcludePattern = (fileName: string, excludePatterns: RegExp[]) =>
|
||
excludePatterns.some((pattern) => pattern.test(fileName));
|
||
|
||
// ----------------------------------------
|
||
function isValidFile(filePath: string, config: Config): boolean {
|
||
const fileName = filePath.split(/[\\/]/).pop()!;
|
||
|
||
if (isExcludeDir(filePath, config.excludeDirs)) return false;
|
||
if (isExcludeFileExtensions(filePath, config.excludeFileExtensions))
|
||
return false;
|
||
if (isExcludePattern(fileName, config.excludePatterns)) return false;
|
||
|
||
const ext = path.extname(filePath);
|
||
return config.includeExtensions.includes(ext);
|
||
}
|
||
// -----------------------------------------
|
||
function generateIndexFile(config: Config) {
|
||
const currentPath = process.cwd();
|
||
const outputPath = path.resolve(currentPath, config.outputDir);
|
||
let exportStatements: string[] = [];
|
||
|
||
// ------ scanDirs forEach start ------------------------
|
||
config.scanDirs.forEach((dir) => {
|
||
// 2. 路径模式保持不变,tinyglobby 能够正确处理
|
||
const scanPattern = path.resolve(currentPath, dir, "**", "*.*");
|
||
|
||
const allFilePath = globSync(scanPattern, {
|
||
absolute: true,
|
||
// 3. 移除了 windowsPathsNoEscape,tinyglobby 默认处理路径更智能
|
||
});
|
||
|
||
const validFiles = allFilePath.filter((filePath) => {
|
||
return isValidFile(filePath, config);
|
||
});
|
||
|
||
if (validFiles.length === 0) {
|
||
console.log(
|
||
`⚠️ 未找到符合条件的文件,跳过生成 ${config.outputFilenameWithExt}`,
|
||
);
|
||
return;
|
||
}
|
||
|
||
validFiles.sort();
|
||
|
||
validFiles.forEach((file) => {
|
||
const relativePath = path.relative(outputPath, file);
|
||
const importPath = `./${relativePath.replace(/\\/g, "/")}`;
|
||
exportStatements.push(`${config.importPrefix} '${importPath}';`);
|
||
});
|
||
});
|
||
|
||
// --------- scanDirs forEach end ----------------
|
||
|
||
const indexFileContent = `
|
||
${config.predefineStatements.join("\n")}
|
||
${exportStatements.join("\n")}
|
||
`.trim();
|
||
|
||
const indexFilePath = path.resolve(
|
||
currentPath,
|
||
config.outputDir,
|
||
config.outputFilenameWithExt,
|
||
);
|
||
|
||
// ✅ 内容比对,避免重复写入
|
||
if (fs.existsSync(indexFilePath)) {
|
||
const old = fs.readFileSync(indexFilePath, "utf8");
|
||
if (old === indexFileContent) {
|
||
console.log(
|
||
`✅ ${config.outputFilenameWithExt} 内容无变化,无需重新生成`,
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
|
||
fs.writeFileSync(indexFilePath, indexFileContent, "utf8");
|
||
console.log(`✅ 成功生成 ${config.outputFilenameWithExt}: ${indexFilePath}`);
|
||
}
|
||
|
||
// --------------------------------------------------
|
||
|
||
try {
|
||
console.log(`🚀 [gen-index] 开始扫描`);
|
||
generateIndexFile(cssConfig);
|
||
generateIndexFile(tsConfig);
|
||
} catch (err) {
|
||
const msg = err instanceof Error ? err.message : String(err);
|
||
console.error(`❌ [gen-index] 执行失败: ${msg}`);
|
||
process.exit(1);
|
||
}
|