91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
import fs from 'fs'
|
|
import process from 'process'
|
|
|
|
process.loadEnvFile()
|
|
|
|
function getFiles(dir: string): string[] {
|
|
return fs.readdirSync(dir).flatMap((name) => {
|
|
const path = `${dir}/${name}`
|
|
if (fs.statSync(path).isDirectory()) {
|
|
return getFiles(path)
|
|
} else {
|
|
return [path]
|
|
}
|
|
})
|
|
}
|
|
|
|
const METADATA_BLOCK_REGEX = /^---\n([\s\S]*?)---\n/m
|
|
const METADATA_REGEX = /^(\w+):(.*)$/gm
|
|
|
|
function readArticleMetadata(path: string): Record<string, string> | null {
|
|
const content = fs.readFileSync(path, { encoding: 'utf8' })
|
|
const match: RegExpExecArray | null = METADATA_BLOCK_REGEX.exec(content)
|
|
if (!match || !match[1]) {
|
|
console.warn(`No metadata for: ${path}`)
|
|
return null
|
|
}
|
|
let subMatch: RegExpExecArray | null = null
|
|
const metadata: Record<string, string> = {
|
|
path: path.replaceAll('/index.md', ''),
|
|
}
|
|
do {
|
|
subMatch = METADATA_REGEX.exec(match[1])
|
|
if (subMatch && subMatch[1] && subMatch[2]) {
|
|
metadata[subMatch[1]] = subMatch[2].trim()
|
|
}
|
|
} while (subMatch)
|
|
return metadata
|
|
}
|
|
|
|
function formatArticlePage(metadata: Record<string, string>, baseHtml: string): string {
|
|
let outHtml = baseHtml
|
|
outHtml = outHtml.replace(/<.*?property="og:url".*?>/gm, '')
|
|
outHtml = outHtml.replace(
|
|
/<\/head>/gm,
|
|
`<meta property="og:url" content="${process.env.VITE_BASE_URL}${metadata.path}/">\n</head>`,
|
|
)
|
|
const blog_title = process.env.VITE_APP_TITLE?.replace(/(<([^>]+)>)/gi, '').trim()
|
|
if (metadata.title) {
|
|
const title = metadata.title.replace(/(<([^>]+)>)/gi, '').trim()
|
|
outHtml = outHtml.replace(/<title>.*?<\/title>/gm, `<title>${blog_title} — ${title}</title>`)
|
|
outHtml = outHtml.replace(/<.*?property="og:title".*?>/gm, '')
|
|
outHtml = outHtml.replace(
|
|
/<\/head>/gm,
|
|
`<meta property="og:title" content="${title}">\n</head>`,
|
|
)
|
|
outHtml = outHtml.replace(/<.*?property="og:description".*?>/gm, '')
|
|
outHtml = outHtml.replace(
|
|
/<\/head>/gm,
|
|
`<meta property="og:description" content="${blog_title}">\n</head>`,
|
|
)
|
|
}
|
|
if (metadata.thumbnail) {
|
|
outHtml = outHtml.replace(/<.*?property="og:image".*?>/gm, '')
|
|
outHtml = outHtml.replace(
|
|
/<\/head>/gm,
|
|
`<meta property="og:image" content="${metadata.thumbnail.replace('./', process.env.VITE_BASE_URL + metadata.path + '/')}">\n</head>`,
|
|
)
|
|
}
|
|
return outHtml
|
|
}
|
|
|
|
const indexContent = fs.readFileSync('dist/index.html', { encoding: 'utf8' })
|
|
|
|
if (!indexContent) {
|
|
console.error('Could not read dist/index.html')
|
|
process.exit(1)
|
|
}
|
|
|
|
getFiles('articles')
|
|
.filter((path) => path.match(/index.md$/))
|
|
.forEach((path) => {
|
|
const metadata = readArticleMetadata(path)
|
|
if (metadata) {
|
|
fs.writeFileSync(
|
|
`dist/${metadata.path}/index.html`,
|
|
formatArticlePage(metadata, indexContent),
|
|
)
|
|
console.info(`Wrote dist/${metadata.path}/index.html`)
|
|
}
|
|
})
|