Files
BitLogger/scripts/generate-docs-data.mjs
T
2026-06-14 16:00:00 +08:00

121 lines
3.8 KiB
JavaScript

import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
import { basename, dirname, extname, resolve } from 'node:path'
import matter from 'gray-matter'
const root = process.cwd()
const docsDir = resolve(root, 'docs')
const apiDir = resolve(docsDir, 'api')
const changesDir = resolve(docsDir, 'changes')
const outFile = resolve(docsDir, '.vitepress', 'generated', 'docs-data.mjs')
function splitWords(input) {
return input
.split(/[^A-Za-z0-9]+/)
.map(part => part.trim())
.filter(Boolean)
}
function formatWord(word) {
const lower = word.toLowerCase()
if (lower === 'api') return 'API'
if (lower === 'json') return 'JSON'
if (lower === 'js') return 'JS'
if (lower === 'wasm') return 'WASM'
if (lower === 'llvm') return 'LLVM'
return lower.charAt(0).toUpperCase() + lower.slice(1)
}
function humanize(input) {
const words = splitWords(input)
if (words.length === 0) return input
return words.map(formatWord).join(' ')
}
function extractTitle(source, fallback) {
const heading = source.match(/^##\s+(.+)$/m)?.[1]?.trim()
return humanize(heading ?? fallback)
}
function readApiDocs() {
const entries = readdirSync(apiDir, { withFileTypes: true })
.filter(entry => entry.isFile())
.filter(entry => extname(entry.name) === '.md')
.filter(entry => !entry.name.startsWith('.'))
.map(entry => {
const file = entry.name
const slug = basename(file, '.md')
const source = readFileSync(resolve(apiDir, file), 'utf8')
const parsed = matter(source)
const data = parsed.data
const keywords = Array.isArray(data['key-word']) ? data['key-word'].map(String) : []
return {
file,
slug,
title: extractTitle(parsed.content, data.name ?? slug),
name: String(data.name ?? slug),
group: String(data.group ?? 'misc'),
category: String(data.category ?? 'misc'),
description: String(data.description ?? ''),
updateTime: data['update-time'] == null ? '' : String(data['update-time']),
keywords,
link: `/api/${slug}`,
}
})
.sort((left, right) => left.title.localeCompare(right.title))
const grouped = [...new Set(entries.map(entry => entry.group))]
.sort((left, right) => humanize(left).localeCompare(humanize(right)))
.map(group => {
const items = entries.filter(entry => entry.group === group)
const categories = [...new Set(items.map(entry => entry.category))]
.sort((left, right) => humanize(left).localeCompare(humanize(right)))
.map(category => ({
id: category,
label: humanize(category),
entries: items.filter(entry => entry.category === category),
}))
return {
id: group,
label: humanize(group),
entryCount: items.length,
categories,
}
})
const categorySummaries = [...new Set(entries.map(entry => entry.category))]
.sort((left, right) => humanize(left).localeCompare(humanize(right)))
.map(category => ({
id: category,
label: humanize(category),
entryCount: entries.filter(entry => entry.category === category).length,
}))
return {
entries,
groups: grouped,
categories: categorySummaries,
}
}
function readChanges() {
return readdirSync(changesDir, { withFileTypes: true })
.filter(entry => entry.isFile())
.filter(entry => extname(entry.name) === '.md')
.filter(entry => entry.name !== 'index.md')
.map(entry => basename(entry.name, '.md'))
.sort((left, right) => right.localeCompare(left, undefined, { numeric: true }))
.map(version => ({
version,
link: `/changes/${version}`,
}))
}
const api = readApiDocs()
const changes = readChanges()
const output = `export const docsData = ${JSON.stringify({ api, changes }, null, 2)}\n`
mkdirSync(dirname(outFile), { recursive: true })
writeFileSync(outFile, output)