Skip to content

Commit 1692b40

Browse files
committed
add accepted/updated metadata
Signed-off-by: Andrew Duffy <andrew@a10y.dev>
1 parent f5faae8 commit 1692b40

3 files changed

Lines changed: 170 additions & 10 deletions

File tree

index.ts

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@ import { watch } from "fs";
44
const isDev = process.argv.includes("--dev");
55
const PORT = 3000;
66

7+
interface GitCommit {
8+
hash: string;
9+
date: Date;
10+
}
11+
12+
interface RFCGitInfo {
13+
accepted: GitCommit | null;
14+
lastUpdated: GitCommit | null; // null if same as accepted or no git history
15+
}
16+
717
interface RFC {
818
number: string;
919
title: string;
1020
filename: string;
1121
html: string;
22+
git: RFCGitInfo;
1223
}
1324

1425
const THEME_SCRIPT = `
@@ -113,9 +124,47 @@ ${list}
113124
return baseHTML("Vortex RFCs", content, "styles.css", liveReload);
114125
}
115126

116-
function rfcPage(rfc: RFC, liveReload: boolean = false): string {
127+
function formatDate(date: Date): string {
128+
return date.toLocaleDateString("en-US", {
129+
year: "numeric",
130+
month: "long",
131+
day: "numeric",
132+
});
133+
}
134+
135+
function rfcPage(rfc: RFC, repoUrl: string | null, liveReload: boolean = false): string {
136+
let gitHeader = "";
137+
138+
if (rfc.git.accepted) {
139+
const acceptedLink = repoUrl
140+
? `<a href="${repoUrl}/commit/${rfc.git.accepted.hash}" class="commit-link">${formatDate(rfc.git.accepted.date)}</a>`
141+
: formatDate(rfc.git.accepted.date);
142+
143+
gitHeader = `
144+
<div class="rfc-meta-header">
145+
<div class="rfc-meta-item">
146+
<span class="rfc-meta-label">Accepted:</span>
147+
${acceptedLink}
148+
</div>`;
149+
150+
if (rfc.git.lastUpdated) {
151+
const updatedLink = repoUrl
152+
? `<a href="${repoUrl}/commit/${rfc.git.lastUpdated.hash}" class="commit-link">${formatDate(rfc.git.lastUpdated.date)}</a>`
153+
: formatDate(rfc.git.lastUpdated.date);
154+
155+
gitHeader += `
156+
<div class="rfc-meta-item">
157+
<span class="rfc-meta-label">Last updated:</span>
158+
${updatedLink}
159+
</div>`;
160+
}
161+
162+
gitHeader += `
163+
</div>`;
164+
}
165+
117166
const content = `
118-
<a href="../" class="back-link">&larr; Back to index</a>
167+
<a href="../" class="back-link">&larr; Back to index</a>${gitHeader}
119168
<article class="rfc-content">
120169
${rfc.html}
121170
</article>`;
@@ -129,6 +178,52 @@ function parseRFCNumber(filename: string): string {
129178
return match?.[1] ?? "0000";
130179
}
131180

181+
async function getGitHubRepoUrl(): Promise<string | null> {
182+
try {
183+
const result = await $`git remote get-url origin`.quiet();
184+
const url = result.stdout.toString().trim();
185+
// Convert git@github.com:user/repo.git to https://github.com/user/repo
186+
if (url.startsWith("git@github.com:")) {
187+
return "https://github.com/" + url.slice(15).replace(/\.git$/, "");
188+
}
189+
// Convert https://github.com/user/repo.git to https://github.com/user/repo
190+
if (url.startsWith("https://github.com/")) {
191+
return url.replace(/\.git$/, "");
192+
}
193+
return null;
194+
} catch {
195+
return null;
196+
}
197+
}
198+
199+
async function getGitHistory(filepath: string): Promise<RFCGitInfo> {
200+
try {
201+
const result = await $`git log --follow --format=%H\ %aI -- ${filepath}`.quiet();
202+
const lines = result.stdout.toString().trim().split("\n").filter(Boolean);
203+
204+
if (lines.length === 0) {
205+
return { accepted: null, lastUpdated: null };
206+
}
207+
208+
const parseCommit = (line: string): GitCommit => {
209+
const [hash, dateStr] = line.split(" ");
210+
return { hash, date: new Date(dateStr) };
211+
};
212+
213+
const mostRecent = parseCommit(lines[0]);
214+
const oldest = parseCommit(lines[lines.length - 1]);
215+
216+
// If only one commit, or same commit, don't show lastUpdated
217+
if (lines.length === 1 || mostRecent.hash === oldest.hash) {
218+
return { accepted: oldest, lastUpdated: null };
219+
}
220+
221+
return { accepted: oldest, lastUpdated: mostRecent };
222+
} catch {
223+
return { accepted: null, lastUpdated: null };
224+
}
225+
}
226+
132227
interface ValidationError {
133228
filename: string;
134229
message: string;
@@ -190,6 +285,9 @@ async function build(liveReload: boolean = false): Promise<number> {
190285
process.exit(1);
191286
}
192287

288+
// Get GitHub repo URL for commit links
289+
const repoUrl = await getGitHubRepoUrl();
290+
193291
const glob = new Bun.Glob("*.md");
194292
const rfcs: RFC[] = [];
195293

@@ -202,8 +300,9 @@ async function build(liveReload: boolean = false): Promise<number> {
202300
const html = Bun.markdown.html(content);
203301
const number = parseRFCNumber(filename);
204302
const title = parseTitle(content, filename);
303+
const git = await getGitHistory(path);
205304

206-
rfcs.push({ number, title, filename, html });
305+
rfcs.push({ number, title, filename, html, git });
207306
}
208307

209308
if (rfcs.length === 0) {
@@ -231,7 +330,7 @@ async function build(liveReload: boolean = false): Promise<number> {
231330

232331
// Generate individual RFC pages
233332
for (const rfc of rfcs) {
234-
const html = rfcPage(rfc, liveReload);
333+
const html = rfcPage(rfc, repoUrl, liveReload);
235334
const outPath = `dist/rfc/${rfc.number}.html`;
236335
await Bun.write(outPath, html);
237336
console.log(`Generated ${outPath}`);

proposals/0000-template.md

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,38 @@
1-
---
2-
author: Adam Gutglick <adam@spiraldb.com>
3-
description: This is a template for future proposals, using frontmatter for metadata.
4-
date: 2025-02-23
5-
---
1+
# RFC 0000 - Template Mode
62

7-
# Example Title
3+
## Goals
4+
5+
1. Create RFCs
6+
1. ??
7+
1. Profit
8+
9+
## Diagrams
10+
11+
Here is an ASCII diagram:
12+
13+
```
14+
╔ ═ ═ ═ ═ ═ ═ ═ ═ ═ ═
15+
16+
║ BitPackedArray
17+
18+
╚│═ ═ ═ ═ ═ ═ ═ ╤ ═ ═
19+
│ │
20+
│ │
21+
│ │
22+
│ │
23+
│ │
24+
│ │
25+
│ │ patch
26+
│ │ indices ╔ ═ ═ ═ ═ ═
27+
┌─────▼─────┐ ├─────────────▶ ArrayRef ║
28+
│░░░░░░░░░░░│ │ ╚ ═ ═ ═ ═ ═
29+
│░░Buffer░░░│ │
30+
│░░░░░░░░░░░│ │ patch
31+
└───────────┘ │ values ╔ ═ ═ ═ ═ ═
32+
encoded └─────────────▶ ArrayRef ║
33+
╚ ═ ═ ═ ═ ═
34+
```
35+
36+
We can have links, like https://github.com/vortex-data
37+
38+
BUT, we can also have [**LINKS**](https://vortex.dev) or [__links__](https://docs.vortex.dev)

styles.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,36 @@ th {
271271
}
272272

273273
/* RFC page specific */
274+
.rfc-meta-header {
275+
display: flex;
276+
flex-wrap: wrap;
277+
gap: 1.5rem;
278+
padding: 1rem;
279+
background: var(--bg-alt);
280+
border: 1px solid var(--border);
281+
border-radius: 4px;
282+
margin-bottom: 1.5rem;
283+
font-size: 0.875rem;
284+
}
285+
286+
.rfc-meta-item {
287+
display: flex;
288+
gap: 0.5rem;
289+
}
290+
291+
.rfc-meta-label {
292+
color: var(--fg-muted);
293+
}
294+
295+
.commit-link {
296+
color: var(--link);
297+
}
298+
299+
.commit-link:hover {
300+
color: var(--link-hover);
301+
text-decoration: underline;
302+
}
303+
274304
.rfc-header {
275305
margin-bottom: 2rem;
276306
padding-bottom: 1rem;

0 commit comments

Comments
 (0)