Files
www/content.js
paul 146d516f24
Deploy website / deploy (push) Successful in 24s
Refactor site generation into a modular content pipeline
2026-09-22 20:51:13 -04:00

72 lines
2.2 KiB
JavaScript

import { execFileSync } from 'node:child_process'
import { readdir, readFile, stat } from 'node:fs/promises'
import { join } from 'node:path'
export const stripSidenotes = (text) => {
let result = ''
for (let index = 0; index < text.length;) {
if (text[index] === '^' && text[index + 1] === '[') {
const end = text.indexOf(']', index + 2)
if (end >= 0) {
index = end + 1
continue
}
}
result += text[index++]
}
return result
}
export const dateFor = async (file) => {
try {
const gitDate = execFileSync(
'git',
['log', '-1', '--date=format-local:%Y-%m-%dT%H:%M:%SZ', '--format=%ad', '--', file],
{ env: { ...process.env, TZ: 'UTC' }, stdio: ['ignore', 'pipe', 'ignore'] },
).toString().trim()
if (gitDate) return gitDate
} catch {}
try {
return (await stat(file)).mtime.toISOString()
} catch {
return ''
}
}
export const readPages = async (dir, { includeDrafts = false } = {}) => {
let entries
try {
entries = await readdir(dir, { withFileTypes: true })
} catch (error) {
if (error.code === 'ENOENT') return []
throw error
}
const markdownEntries = entries
.filter((entry) => entry.isFile() && entry.name.endsWith('.md') && entry.name !== '.md'
&& (includeDrafts || !entry.name.startsWith('.')))
.sort((a, b) => a.name.localeCompare(b.name))
const pages = await Promise.all(markdownEntries.map(async (entry) => {
const file = join(dir, entry.name)
const source = await readFile(file, 'utf8')
const titleLine = source.split(/\r?\n/).find((line) => line.startsWith('# '))
if (!titleLine) return undefined
const draft = entry.name.startsWith('.')
const name = (draft ? entry.name.slice(1) : entry.name).slice(0, -3)
if (!name) return undefined
return {
name,
title: stripSidenotes(titleLine.slice(2).trim()),
file,
source,
date: await dateFor(file),
draft,
}
}))
const byName = new Map()
for (const page of pages.filter(Boolean)) {
const existing = byName.get(page.name)
if (!existing || (existing.draft && !page.draft)) byName.set(page.name, page)
}
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name))
}