You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

98 lines
2.5 KiB
TypeScript

4 months ago
#!/bin/env deno run
import { globber } from "https://deno.land/x/globber@0.1.0/mod.ts"
interface FileIndex {
title: string
slug: string
abstr: string
date: string
readingTimeSlow: number
readingTimeFast: number
}
const cwd = './blog/'
const outputPath = './blog/index.md'
const fileIndex: FileIndex[] = []
const fileIter = globber({ cwd, include: ["????-??-??*.md"] })
const decoder = new TextDecoder('utf-8')
const encoder = new TextEncoder()
const header = `*Sometimes, I write long-form articles about a topic that I find interesting. I use this as a way to dive deeper into a topic, while often create an example project on the side.*
Last updated: ${(new Date()).toISOString().slice(0,10)}
`
const template = `<article class="blog">
<time datetime="%DATE%">%DATE%</time>
<div>
<a href="/blog/%SLUG%.html">%TITLE%</a>
<span class="reading-time">(%READING_TIME_FAST% to %READING_TIME_SLOW% minutes)</span>
</div>
<p>
%ABSTRACT%
</p>
</article>
`
function getAbstract(lines: string[]): string {
const sep = '<!-- more -->'
const sep2 = '<!--more-->'
let foundSep = false
return lines.slice(3).filter(line => {
if (foundSep) return false
if (line.indexOf(sep) >= 0 || line.indexOf(sep2) >= 0) {
foundSep = true
return false
}
return true
}).join('\n').trim()
}
function render(fi: FileIndex) {
return template
.replaceAll('%DATE%', fi.date)
.replaceAll('%TITLE%', fi.title)
.replaceAll('%SLUG%', fi.slug)
.replaceAll('%ABSTRACT%', fi.abstr)
.replaceAll('%READING_TIME_FAST%', fi.readingTimeFast)
.replaceAll('%READING_TIME_SLOW%', fi.readingTimeSlow)
}
for await (const file of fileIter) {
if (file.isDirectory) {
console.log('ignoring directory', file.relative)
break
}
const path = file.absolute
const date = file.relative.slice(0, 10)
const slug = file.relative.slice(0, -3)
const raw = await Deno.readFile(path)
const text = decoder.decode(raw)
const words = text.trim().split(/\s+/).length
const lines = text.split('\n')
const title = lines[0].slice(2)
const abstr = getAbstract(lines)
// calculates estimated reading times: [fast, slow]
// wpm numbers from https://thereadtime.com/
const readingTimeFast = Math.round(words / 207)
const readingTimeSlow = Math.round(words / 167)
fileIndex.push({ title, slug, abstr, date, readingTimeFast, readingTimeSlow })
}
const output = fileIndex
.sort((a, b) => a.date.localeCompare(b.date) * -1)
.map(render)
.join('\n')
Deno.writeFile(outputPath, encoder.encode(header+output))