/Sources\/([A-Z][0-9A-Za-z]*\/[A-Z][0-9A-Za-z]*)\.djot$/u.exec(path)
?.[1]?.replace?.("/", ":");
-const listOfInternalLinks = (references) => ({
+const listOfInternalLinks = (references, wrapper = ($) => $) => ({
tag: "bullet_list",
tight: true,
style: "*",
tag: "list_item",
children: [{
tag: "para",
- children: [{
+ children: [wrapper({
tag: "link",
attributes: {
"data-realm": "internal",
},
reference,
children: [],
- }],
+ })],
}],
};
},
),
});
+const diffReferences = async (hash) => {
+ const diff = new Deno.Command("git", {
+ args: [
+ "diff-tree",
+ "-r",
+ "-z",
+ "--name-only",
+ "--no-renames",
+ "--diff-filter=AM",
+ hash,
+ ],
+ stdout: "piped",
+ stderr: "piped",
+ }).spawn();
+ const [diffNames] = await Promise.allSettled([
+ new Response(diff.stdout).text(),
+ new Response(diff.stderr).text(),
+ ]).then(logErrorsAndCollectResults);
+ return references(diffNames.split("\0")); // returns an iterable
+};
+
function* references(paths) {
for (const path of paths) {
const reference = getReferenceFromPath(path);
} else {
/* do nothing */
}
- const diff = new Deno.Command("git", {
- args: [
- "diff",
- "-z",
- "--name-only",
- "--no-renames",
- "--diff-filter=AM",
- commit,
- ],
- stdout: "piped",
- stderr: "piped",
- }).spawn();
- const [diffNames] = await Promise.allSettled([
- new Response(diff.stdout).text(),
- new Response(diff.stderr).text(),
- ]).then(logErrorsAndCollectResults);
- return [...references(diffNames.split("\0"))];
+ const results = new Array(6);
+ const seen = new Set();
+ let recency = 5;
+ let current;
+ do {
+ const show = new Deno.Command("git", {
+ args: [
+ "show",
+ "-s",
+ "--format=%H%x00%cI%x00%cD",
+ recency ? `HEAD~${5 - recency}` : commit,
+ ],
+ stdout: "piped",
+ stderr: "piped",
+ }).spawn();
+ const [
+ [hash, dateTime, humanReadable],
+ ] = await Promise.allSettled([
+ new Response(show.stdout).text().then((rev) =>
+ rev.trim().split("\0")
+ ),
+ new Response(show.stderr).text(),
+ ]).then(logErrorsAndCollectResults);
+ const refs = [];
+ current = hash;
+ for (const ref of (await diffReferences(current))) {
+ if (seen.has(ref)) {
+ /* do nothing */
+ } else {
+ refs.push(ref);
+ seen.add(ref);
+ }
+ }
+ results[recency] = { dateTime, humanReadable, refs };
+ } while (recency-- > 0 && current && current != commit);
+ return results;
})(),
...Array.from(
pages.keys(),
const { content, navigation } = (() => {
const navigation = [];
if (pageRef == "Special:RecentlyChanged") {
- navigation.push(
- listOfInternalLinks(recentlyChanged),
- );
+ navigation.push({
+ tag: "bullet_list",
+ attributes: { class: "recent-changes" },
+ tight: true,
+ style: "*",
+ children: Array.from(function* () {
+ for (
+ const [index, result] of recentlyChanged
+ .entries()
+ ) {
+ if (result != null) {
+ const {
+ dateTime,
+ humanReadable,
+ refs,
+ } = result;
+ yield* listOfInternalLinks(refs, (link) => ({
+ tag: index ? "strong" : "span",
+ attributes: { "data-recency": `${index}` },
+ children: [
+ link,
+ str` `,
+ rawInline`<small>(<time dateTime="${dateTime}">`,
+ str`${humanReadable}`,
+ rawInline`</time>)</small>`,
+ ],
+ })).children;
+ } else {
+ /* do nothing */
+ }
+ }
+ }()).reverse(),
+ });
} else {
isNavigationPage = false;
return { content: e.children, navigation };
level: 1,
children: [str`${title}`],
},
- rawBlock`<details open="">`,
+ rawBlock`<details id="navigation-about" open="">`,
rawBlock`<summary>about this listing</summary>`,
...e.children,
rawBlock`</details>`,
if (attributes["data-realm"] == "internal") {
delete e.reference;
if (redLinks.has(reference)) {
- e.destination = `/Special:NotFound?path=/${reference}`;
+ e.destination =
+ `/Special:NotFound?path=/${reference}`;
attributes["data-notfound"] = "";
} else {
e.destination = `/${reference}`;