import fs from "fs"; import path from "path"; import { globSync } from "glob"; interface Config { targetDirs: string[]; includeExtensions: string[]; excludeKeywords: { dirs: string[]; fileSuffixes: string[]; filePatterns: RegExp[]; }; } const CONFIG: Config = { targetDirs: ["src"], includeExtensions: [".ts", ".tsx", ".vue"], excludeKeywords: { dirs: ["__tests__", "tests", "story", "stories", "types"], fileSuffixes: [".d.ts"], filePatterns: [ /^index\.(ts|tsx|js|jsx)$/, /\.(test|spec)\./, /\.(story|stories)\./, ], }, }; const normalizePath = (p: string) => p.replace(/\\/g, "/"); const isInExcludeDir = (filePath: string) => { const normalized = normalizePath(filePath); return CONFIG.excludeKeywords.dirs.some((dir) => normalized.includes(`/${dir}/`), ); }; const isExcludeSuffix = (filePath: string) => CONFIG.excludeKeywords.fileSuffixes.some((suffix) => filePath.endsWith(suffix), ); const isMatchExcludePattern = (fileName: string) => CONFIG.excludeKeywords.filePatterns.some((pattern) => pattern.test(fileName)); function isValidFile(filePath: string): boolean { const fileName = filePath.split(/[\\/]/).pop()!; if (isInExcludeDir(filePath)) return false; if (isExcludeSuffix(filePath)) return false; if (isMatchExcludePattern(fileName)) return false; const ext = path.extname(filePath); return CONFIG.includeExtensions.includes(ext); } function generateIndexFile(dirPath: string) { const searchPattern = path.resolve(dirPath, "**", "*.*"); const allFiles = globSync(searchPattern, { nodir: true, absolute: true, windowsPathsNoEscape: true, dot: false, follow: true, }); const validFiles = allFiles.filter(isValidFile); if (validFiles.length === 0) { console.log("⚠️ 未找到符合条件的文件,跳过生成 index.ts"); return; } validFiles.sort(); const exportStatements = validFiles.map((file) => { const relPath = path.relative(dirPath, file); const importPath = `./${relPath .replace(/\.[^.]+$/, "") .replace(/\\/g, "/")}`; return `export * from '${importPath}';`; }); const indexContent = ` import './index.css'; ${exportStatements.join("\n")} `.trim(); const indexFilePath = path.resolve(dirPath, "index.ts"); // ✅ 内容比对,避免重复写入 if (fs.existsSync(indexFilePath)) { const old = fs.readFileSync(indexFilePath, "utf8"); if (old === indexContent) { console.log("✅ index.ts 内容无变化,无需重新生成"); return; } } fs.writeFileSync(indexFilePath, indexContent, "utf8"); console.log(`✅ 成功生成 index.ts: ${indexFilePath}`); } // 脚本入口 const [targetDir] = CONFIG.targetDirs; if (!targetDir) { console.error("❌ CONFIG.targetDirs 不能为空"); process.exit(1); } const absTargetDir = path.resolve(process.cwd(), targetDir); try { console.log(`🚀 开始扫描目录: ${absTargetDir}`); generateIndexFile(absTargetDir); } catch (err) { const msg = err instanceof Error ? err.message : String(err); console.error(`❌ [gen-index-ts] 执行失败: ${msg}`); process.exit(1); }