Files
xrpl-dev-portal/@theme/plugins/index-pages.js
2026-04-28 17:59:03 -07:00

96 lines
3.0 KiB
JavaScript

// The purpose of this plugin is to get a list of pages that are "children" of
// the current page and pass along their frontmatter as well as the path that
// can be used to link to those pages from other components.
// It uses experimental Redocly plugin interface stuff that is expected
// to be exposed in a "nicer" way in some theoretical future release.
// The ts-ignore and TODOs are more for Redocly's notes than for XRPLF.
// @ts-check
import { readSharedData } from '@redocly/realm/dist/server/utils/shared-data.js'; // TODO: export function from root package
const INDEX_PAGE_INFO_DATA_KEY = 'index-page-items';
export function indexPages() {
/** @type {import("@redocly/realm/dist/server/types").ExternalPlugin } */
const instance = {
id: 'index-pages',
// hook that gets executed after all routes were created
async afterRoutesCreated(actions, { cache }) {
// get all the routes that are ind pages
const indexRoutes = actions
.getAllRoutes()
.filter((route) => route.metadata?.indexPage);
for (const route of indexRoutes) {
// @ts-ignore this uses some internals, we will expose them in nicer way in the future releases
const sidebarId = actions.routesSharedData.get(route.slug)?.['sidebar']; // TODO: implement a helper function for this
/** @type {any} */
const sidebar = await readSharedData(sidebarId, actions.outdir);
if (!sidebar) {
console.log('[warn] Index route used with no sidebar', route.fsPath);
continue;
}
const item = findItemDeep(sidebar.items, route.fsPath);
const childrenPaths = (item.items || [])
.map(
// @ts-ignore
(item) => item.fsPath
)
.filter(Boolean);
const childRoutes = childrenPaths.map(
// @ts-ignore
(fsPath) =>
actions.getRouteByFsPath(fsPath),
);
const childRoutesData = await Promise.all(
childRoutes.map(
// @ts-ignore
async (route) => {
const { data } = await cache.load(
route.fsPath,
'markdown-frontmatter',
);
const slug = route.slug;
const title = await route.getNavText();
return {
...data?.frontmatter,
slug,
title,
};
}),
);
const sharedDataId = await actions.createSharedData(
route.slug + '_' + INDEX_PAGE_INFO_DATA_KEY,
childRoutesData,
);
actions.addRouteSharedData(
route.slug,
INDEX_PAGE_INFO_DATA_KEY,
sharedDataId,
);
}
},
};
return instance;
}
// @ts-ignore
function findItemDeep(items, fsPath) {
for (const item of items) {
if (item.fsPath === fsPath) {
return item;
}
if (item.items) {
// @ts-ignore
const found = findItemDeep(item.items, fsPath);
if (found) {
return found;
}
}
}
}