174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
import path from 'path'
|
|
import matter from 'gray-matter'
|
|
import moment from 'moment'
|
|
import fs from 'fs-extra'
|
|
// @ts-ignore
|
|
import shortHash from 'short-hash'
|
|
import stringify from 'fast-json-stable-stringify'
|
|
import glob from 'fast-glob'
|
|
|
|
export type DataType = 'posts' | 'slides'
|
|
|
|
export interface IData {
|
|
teaser?: string
|
|
full: string
|
|
}
|
|
|
|
export default class ApiBuilder {
|
|
_hash: Record<DataType, Record<string, string>> = {
|
|
posts: {},
|
|
slides: {},
|
|
}
|
|
|
|
_tag: Record<DataType, Record<string, number>> = {
|
|
posts: {},
|
|
slides: {},
|
|
}
|
|
|
|
_header: Record<DataType, any[]> = {
|
|
posts: [],
|
|
slides: [],
|
|
}
|
|
|
|
_data: Record<DataType, Record<string, IData>> = {
|
|
posts: {},
|
|
slides: {},
|
|
}
|
|
|
|
loadFile (dirName: DataType, fileName: string) {
|
|
const ROOT = path.join('data', dirName)
|
|
|
|
const raw = fs.readFileSync(path.join(ROOT, fileName), 'utf8')
|
|
|
|
const m = matter(raw)
|
|
const p = path.parse(fileName)
|
|
m.data = {
|
|
...m.data,
|
|
name: p.name,
|
|
path: fileName,
|
|
}
|
|
|
|
if (m.data.date) {
|
|
let mm = moment(m.data.date)
|
|
mm = mm.add(-mm.utcOffset(), 'minute')
|
|
|
|
Object.assign(m.data, {
|
|
date: mm.toISOString(),
|
|
y: mm.format('YYYY'),
|
|
mo: mm.format('MM'),
|
|
})
|
|
}
|
|
|
|
let data: IData = {
|
|
full: m.content,
|
|
}
|
|
|
|
if (dirName === 'posts') {
|
|
const [teaser, remaining] = m.content.split(/\n===\n(.+)/s)
|
|
data = {
|
|
teaser,
|
|
full: `${teaser}\n${remaining || ''}`,
|
|
}
|
|
}
|
|
|
|
return {
|
|
header: m.data,
|
|
data,
|
|
}
|
|
}
|
|
|
|
loadDir (dirName: DataType) {
|
|
const ROOT = path.join('data', dirName)
|
|
const now = new Date().toISOString()
|
|
|
|
glob.sync('**/*.md', {
|
|
cwd: ROOT,
|
|
}).map((f) => {
|
|
const { header, data } = this.loadFile(dirName, f)
|
|
this._hash[dirName][f] = shortHash(data.full)
|
|
|
|
if (dirName === 'posts' && header.date && header.date < now && header.path.startsWith('blog/')) {
|
|
if (Array.isArray(header.tag)) {
|
|
for (const t of header.tag) {
|
|
this._tag[dirName][t] = (this._tag[dirName][t] || 0) + 1
|
|
}
|
|
}
|
|
}
|
|
|
|
this._header[dirName].push(header)
|
|
this._data[dirName][f] = data
|
|
})
|
|
|
|
this._header[dirName] = this._header[dirName].sort((h1, h2) => {
|
|
if (typeof h1.date === 'string' && typeof h2.date === 'string') {
|
|
return -h1.date.localeCompare(h2.date)
|
|
}
|
|
return 0
|
|
})
|
|
|
|
this._hash[dirName]._header = shortHash(stringify(this._header[dirName]))
|
|
|
|
return {
|
|
header: this._header[dirName],
|
|
hash: this._hash[dirName]._header,
|
|
tag: this._tag[dirName],
|
|
}
|
|
}
|
|
|
|
emit () {
|
|
const dst = 'static/build'
|
|
|
|
this.loadDir('posts')
|
|
this.loadDir('slides')
|
|
|
|
/**
|
|
* Emit hash
|
|
*/
|
|
console.log('Emitting hash')
|
|
fs.ensureDirSync(`${dst}/hash`)
|
|
fs.writeFileSync(`${dst}/hash/posts.json`, JSON.stringify(this._hash.posts))
|
|
fs.writeFileSync(`${dst}/hash/slides.json`, JSON.stringify(this._hash.slides))
|
|
|
|
/**
|
|
* Emit header
|
|
*/
|
|
console.log('Emitting header')
|
|
fs.ensureDirSync(`${dst}/header`)
|
|
fs.writeFileSync(`${dst}/header/posts.json`, JSON.stringify(this._header.posts))
|
|
fs.writeFileSync(`${dst}/header/slides.json`, JSON.stringify(this._header.slides))
|
|
|
|
/**
|
|
* Emit tag
|
|
*/
|
|
console.log('Emitting tag')
|
|
fs.ensureDirSync(`${dst}/tag`)
|
|
fs.writeFileSync(`${dst}/tag/posts.json`, JSON.stringify(this._tag.posts))
|
|
|
|
/**
|
|
* Emit posts
|
|
*/
|
|
console.log('Emitting blog entries')
|
|
for (const [p, data] of Object.entries(this._data.posts)) {
|
|
fs.ensureFileSync(`${dst}/teaser/${p}`)
|
|
fs.ensureFileSync(`${dst}/full/${p}`)
|
|
|
|
fs.writeFileSync(`${dst}/teaser/${p}`, data.teaser)
|
|
fs.writeFileSync(`${dst}/full/${p}`, data.full)
|
|
}
|
|
|
|
/**
|
|
* Emit slides
|
|
*/
|
|
console.log('Emitting slides')
|
|
for (const [p, data] of Object.entries(this._data.slides)) {
|
|
fs.ensureFileSync(`${dst}/slides/${p}`)
|
|
|
|
fs.writeFileSync(`${dst}/slides/${p}`, data.full)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof require !== 'undefined' && require.main === module) {
|
|
new ApiBuilder().emit()
|
|
}
|