import { readdir, readFile, writeFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import path from 'node:path'; const root = process.cwd(); const reportsRoot = path.join(root, 'reports'); const output = path.join(root, 'data', 'reports.json'); const categoryNames = { daily: '每日复盘', intraday: '盘中项目', sector: '行业观察', stock: '个股跟踪' }; const files = []; async function walk(dir) { if (!existsSync(dir)) return; for (const item of await readdir(dir, { withFileTypes: true })) { const full = path.join(dir, item.name); if (item.isDirectory()) await walk(full); else if (item.name.endsWith('.html')) files.push(full); } } await walk(reportsRoot); const records = []; for (const file of files) { const rel = path.relative(root, file).split(path.sep).join('/'); const parts = rel.split('/'); const category = parts[1]; const match = parts.at(-1).match(/^(\d{4}-\d{2}-\d{2})-(.+)\.html$/); if (!match) { console.warn(`Skipped (expected YYYY-MM-DD-slug.html): ${rel}`); continue; } const [, date, slug] = match; const html = await readFile(file, 'utf8'); const title = html.match(/(.*?)<\/title>/i)?.[1]?.trim() || slug.replaceAll('-', ' '); const summary = html.match(/<meta\s+name=["']description["']\s+content=["'](.*?)["']/i)?.[1] || '打开查看详细研究内容'; records.push({ id: `${category}-${date}-${slug}`, category, categoryName: categoryNames[category] || category, date, title, summary, tags: [category.toUpperCase()], path: rel }); } records.sort((a, b) => b.date.localeCompare(a.date) || a.title.localeCompare(b.title)); await writeFile(output, `${JSON.stringify(records, null, 2)}\n`); console.log(`Indexed ${records.length} report(s) → ${path.relative(root, output)}`);