1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| const fs = require('fs'); const path = require('path'); const toml = require('toml');
class HugoMigrator { async migrate(hugoDir, hexoDir) { await this.migrateContent(hugoDir, hexoDir); await this.migrateTheme(hugoDir, hexoDir); await this.migrateConfig(hugoDir, hexoDir); }
async migrateContent(hugoDir, hexoDir) { const contentDir = path.join(hugoDir, 'content'); await this.processDirectory(contentDir, hexoDir); }
async processDirectory(dir, hexoDir) { const items = fs.readdirSync(dir); for (const item of items) { const itemPath = path.join(dir, item); const stat = fs.statSync(itemPath); if (stat.isDirectory()) { await this.processDirectory(itemPath, hexoDir); } else if (item.endsWith('.md')) { await this.convertHugoPost(itemPath, hexoDir); } } }
async convertHugoPost(inputPath, hexoDir) { const content = fs.readFileSync(inputPath, 'utf8'); const { data, content: body } = this.parseHugoPost(content); const date = new Date(data.date); const filename = `${date.toISOString().split('T')[0]}-${this.slugify(data.title)}.md`; const relativePath = path.relative(path.join(inputPath, '../../'), inputPath); const outputDir = path.join(hexoDir, 'source/_posts', path.dirname(relativePath)); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } const hexoPost = { title: data.title, date: date.toISOString(), categories: this.extractCategories(data), tags: data.tags || [], content: body }; const outputPath = path.join(outputDir, filename); const contentStr = this.formatHexoPost(hexoPost); fs.writeFileSync(outputPath, contentStr); }
parseHugoPost(content) { const lines = content.split('\n'); const frontMatter = []; let isFrontMatter = false; let contentStart = 0; for (let i = 0; i < lines.length; i++) { if (lines[i] === '+++') { if (!isFrontMatter) { isFrontMatter = true; } else { contentStart = i + 1; break; } } else if (isFrontMatter) { frontMatter.push(lines[i]); } } const tomlContent = frontMatter.join('\n'); const data = toml.parse(tomlContent); const body = lines.slice(contentStart).join('\n'); return { data, content: body }; }
extractCategories(data) { if (data.categories) { return Array.isArray(data.categories) ? data.categories : [data.categories]; } return []; }
slugify(text) { return text.toLowerCase() .replace(/[^\w\s-]/g, '') .replace(/[\s_-]+/g, '-') .replace(/^-+|-+$/g, ''); } }
|