djot.applyFilter(ast, () => {
let titleSoFar = null; // used to collect strs from headings
return {
- doc: {
- enter: (_) => {},
- exit: (e) => {
- const links_section = [];
- if (internalLinks.size || externalLinks.size) {
- links_section.push(
- rawBlock`<nav id="links">`,
- {
- tag: "heading",
- level: 2,
- children: [str`this page contains links`],
- },
- );
- if (internalLinks.size) {
- links_section.push(
- rawBlock`<details open="">`,
- rawBlock`<summary>on this wiki</summary>`,
- listOfInternalLinks(internalLinks),
- rawBlock`</details>`,
- );
- } else {
- /* do nothing */
- }
- if (externalLinks.size) {
- links_section.push(
- rawBlock`<details open="">`,
- rawBlock`<summary>elsewhere on the Web</summary>`,
- {
- tag: "bullet_list",
- tight: true,
- style: "*",
- children: Array.from(
- externalLinks,
- ([destination, text]) => ({
- tag: "list_item",
- children: [{
- tag: "para",
- children: [{
- tag: "link",
- attributes: { "data-realm": "external" },
- destination,
- children: text
- ? [
- rawInline`<cite>`,
- str`${text}`,
- rawInline`</cite>`,
- ]
- : [
- rawInline`<code>`,
- str`${destination}`,
- rawInline`</code>`,
- ],
- }],
- }],
- }),
- ),
- },
- rawBlock`</details>`,
- );
- } else {
- /* do nothing */
- }
- links_section.push(
- rawBlock`</nav>`,
- );
- } else {
- /* do nothing */
- }
- e.children.push(
- rawBlock`<footer>`,
- rawBlock`${"\uFFFF"}`, // footnote placeholder
- ...links_section,
- rawBlock`</footer>`,
- );
- },
- },
hard_break: {
enter: (_) => {
if (titleSoFar != null) {
),
]).then(logErrorsAndCollectResults);
promises.length = 0;
- const redLinks = (() => {
- const result = new Set();
- for (const page of pages.values()) {
+ const { redLinks, subpages } = (() => {
+ const redLinks = new Set();
+ const subpages = new Map();
+ for (const [pageRef, page] of pages) {
+ let superRef = pageRef;
+ while (
+ (superRef = superRef.substring(0, superRef.indexOf("/")))
+ ) {
+ // Iterate over potential superpages and record them if they
+ // actually exist.
+ if (pages.has(superRef)) {
+ // There is a superpage for the current page; record it.
+ if (subpages.has(superRef)) {
+ // The identified superpage already has other subpages.
+ subpages.get(superRef).add(pageRef);
+ } else {
+ // The identified superpage does not already have other
+ // subpages.
+ subpages.set(superRef, new Set([pageRef]));
+ }
+ break;
+ } else {
+ // The superpage for the current page has not been found
+ // yet.
+ /* do nothing */
+ }
+ }
for (const link of page.internalLinks()) {
+ // Iterate over the internal links of the current page and
+ // ensure they are all defined.
if (pages.has(link)) {
+ // The link was defined.
continue;
} else {
- result.add(link);
+ // The link was not defined; it is a redlink.
+ redLinks.add(link);
}
}
}
- return result;
+ return { redLinks, subpages };
})();
- for (
- const [pageRef, { ast, namespace, sections, source }] of pages
- ) {
+ for (const [pageRef, page] of pages) {
+ const { ast, sections, source } = page;
const title = sections.main?.title ?? pageRef;
+ const internalLinks = new Set(page.internalLinks());
+ const externalLinks = new Map(page.externalLinks());
+ const subpageRefs = subpages.get(pageRef) ?? new Set();
djot.applyFilter(ast, () => {
let isNavigationPage = true;
return {
doc: {
enter: (e) => {
+ const seeAlsoSection = [];
+ const linksSection = [];
+ if (subpageRefs.size) {
+ seeAlsoSection.push(
+ rawBlock`<nav id="seealso">`,
+ {
+ tag: "heading",
+ level: 2,
+ children: [
+ str`see also`,
+ ],
+ },
+ rawBlock`<section id="subpages">`,
+ {
+ tag: "heading",
+ level: 3,
+ children: [
+ str`subpages`,
+ ],
+ },
+ listOfInternalLinks(subpageRefs),
+ rawBlock`</section>`,
+ rawBlock`</nav>`,
+ );
+ } else {
+ /* do nothing */
+ }
+ if (internalLinks.size || externalLinks.size) {
+ linksSection.push(
+ rawBlock`<nav id="links">`,
+ {
+ tag: "heading",
+ level: 2,
+ children: [str`this page contains links`],
+ },
+ );
+ if (internalLinks.size) {
+ linksSection.push(
+ rawBlock`<details open="">`,
+ rawBlock`<summary>on this wiki</summary>`,
+ listOfInternalLinks(internalLinks),
+ rawBlock`</details>`,
+ );
+ } else {
+ /* do nothing */
+ }
+ if (externalLinks.size) {
+ linksSection.push(
+ rawBlock`<details open="">`,
+ rawBlock`<summary>elsewhere on the Web</summary>`,
+ {
+ tag: "bullet_list",
+ tight: true,
+ style: "*",
+ children: Array.from(
+ externalLinks,
+ ([destination, text]) => ({
+ tag: "list_item",
+ children: [{
+ tag: "para",
+ children: [{
+ tag: "link",
+ attributes: { "data-realm": "external" },
+ destination,
+ children: text
+ ? [
+ rawInline`<cite>`,
+ str`${text}`,
+ rawInline`</cite>`,
+ ]
+ : [
+ rawInline`<code>`,
+ str`${destination}`,
+ rawInline`</code>`,
+ ],
+ }],
+ }],
+ }),
+ ),
+ },
+ rawBlock`</details>`,
+ );
+ } else {
+ /* do nothing */
+ }
+ linksSection.push(
+ rawBlock`</nav>`,
+ );
+ } else {
+ /* do nothing */
+ }
+ const childrenAndLinks = [
+ ...e.children,
+ ...seeAlsoSection,
+ rawBlock`<footer>`,
+ rawBlock`${"\uFFFF"}`, // footnote placeholder
+ ...linksSection,
+ rawBlock`</footer>`,
+ ];
const { content, navigation } = (() => {
const navigation = [];
if (pageRef == "Special:RecentlyChanged") {
});
} else {
isNavigationPage = false;
- return { content: e.children, navigation };
+ return { content: childrenAndLinks, navigation };
}
return {
content: [
rawBlock`<details id="navigation-about" open="">`,
rawBlock`<summary>about this listing</summary>`,
rawBlock`<article>`,
- ...e.children,
+ ...childrenAndLinks,
rawBlock`</article>`,
rawBlock`</details>`,
],