Files
releases/docs/docusaurus.config.js
T
Charlie Egan ffd7d46ee4 website: Various updates to node and website deps (#8768)
Replaces https://github.com/open-policy-agent/opa/pull/8762

Original dependabot updates:

Bumps the website group in /docs with 9 updates:

| Package | From | To |
| --- | --- | --- |
|
[@floating-ui/react](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/react)
| `0.27.18` | `0.27.19` |
|
[@iconify/react](https://github.com/iconify/iconify/tree/HEAD/components/react)
| `6.0.0` | `6.0.2` |
| [@mermaid-js/layout-elk](https://github.com/mermaid-js/mermaid) |
`0.1.9` | `0.2.1` |
| [eslint](https://github.com/eslint/eslint) | `9.39.2` | `10.4.1` |
| [glob](https://github.com/isaacs/node-glob) | `11.1.0` | `13.0.6` |
| [js-yaml](https://github.com/nodeca/js-yaml) | `4.1.1` | `4.2.0` |
| [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) |
`0.21.0` | `0.22.1` |
| [recharts](https://github.com/recharts/recharts) | `3.7.0` | `3.8.1` |
|
[baseline-browser-mapping](https://github.com/web-platform-dx/baseline-browser-mapping)
| `2.10.20` | `2.10.33` |


I have also made some updates to use node 24.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Charlie Egan <charlie_egan@apple.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-11 13:23:17 +00:00

726 lines
24 KiB
JavaScript

const { themes } = require("prism-react-renderer");
const lightCodeTheme = themes.github;
const darkCodeTheme = {
...themes.dracula,
styles: [
...themes.dracula.styles,
{
types: ["atrule"],
style: { color: "rgb(139, 233, 253)" },
},
],
};
const semver = require("semver");
import fs from "fs/promises";
import { loadPages } from "./src/lib/ecosystem/loadPages.js";
import { loadEvents } from "./src/lib/events/loadEvents.js";
import { markdownExportPlugin } from "./src/lib/plugins/markdownExport.js";
import { loadRules } from "./src/lib/projects/regal/loadRules.js";
import { loadSurveyEventData, loadSurveyEventMetadata, loadSurveyQuestions } from "./src/lib/surveys/loadSurveyData.js";
const path = require("path");
const yaml = require("js-yaml");
const baseUrl = "/";
// With JSDoc @type annotations, IDEs can provide config autocompletion
/** @type {import("@docusaurus/types").DocusaurusConfig} */
(
module.exports = {
title: "Open Policy Agent",
tagline: "Policy-based control for cloud native environments",
url: "https://openpolicyagent.org",
baseUrl: baseUrl,
trailingSlash: false,
// when BUILD_VERSION is set (release builds), warn on broken links/anchors so we don't break main
// when not set (PR checks), throw to flag issues for developers
onBrokenLinks: process.env.BUILD_VERSION ? "warn" : "throw",
onBrokenAnchors: process.env.BUILD_VERSION ? "warn" : "throw",
presets: [
[
"@docusaurus/preset-classic",
/** @type {import("@docusaurus/preset-classic").Options} */
{
docs: {
path: "docs",
routeBasePath: "/docs/",
breadcrumbs: false,
sidebarPath: require.resolve("./src/lib/sidebars.js"),
},
blog: false,
theme: {
customCss: require.resolve("./src/css/custom.css"),
},
},
],
],
customFields: {
buildVersion: process.env.BUILD_VERSION,
},
markdown: {
hooks: { onBrokenMarkdownLinks: "throw" },
mermaid: true,
},
themes: ["@docusaurus/theme-mermaid"],
themeConfig: {
colorMode: {
defaultMode: "light",
disableSwitch: false,
respectPrefersColorScheme: true,
},
metadata: [
{ name: "msapplication-TileColor", content: "#2b5797" },
{ name: "theme-color", content: "#ffffff" },
],
headTags: [
{
tagName: "link",
attributes: {
rel: "icon",
type: "image/png",
href: "/favicon-96x96.png",
sizes: "96x96",
},
},
{
tagName: "link",
attributes: {
rel: "icon",
type: "image/svg+xml",
href: "/favicon.svg",
},
},
{
tagName: "link",
attributes: {
rel: "shortcut icon",
href: "/favicon.ico",
},
},
{
tagName: "link",
attributes: {
rel: "apple-touch-icon",
sizes: "180x180",
href: "/apple-touch-icon.png",
},
},
{
tagName: "meta",
attributes: {
name: "apple-mobile-web-app-title",
content: "OPA",
},
},
{
tagName: "link",
attributes: {
rel: "manifest",
href: "/site.webmanifest",
},
},
],
navbar: {
title: "Open Policy Agent",
logo: {
alt: "OPA Logo",
src: "img/nav/logo.png",
},
items: [
{
// Based on implementation outlined here:
// https://github.com/facebook/docusaurus/issues/7227#issue-1212117180
type: "custom-currentVersionNavbarItem",
position: "left",
},
{ to: "/docs/", label: "Docs", position: "right" },
{
type: "dropdown",
label: "Resources",
position: "right",
items: [
{ to: "/security", label: "Security" },
{ to: "/support", label: "Support" },
{ to: "/community", label: "Community" },
{ to: "/survey", label: "Survey" },
{ href: "https://blog.openpolicyagent.org/", label: "Blog" },
],
},
{
type: "dropdown",
label: "Projects",
position: "right",
items: [
{ to: "/docs", label: "OPA" },
{ to: "/projects/regal", label: "Regal" },
{
type: "html",
value: "<hr style=\"margin: 0.3rem 1rem\">",
},
{ href: "https://open-policy-agent.github.io/gatekeeper/website/", label: "OPA Gatekeeper" },
{ href: "https://www.conftest.dev", label: "Conftest" },
],
},
{ to: "/ecosystem/", label: "Ecosystem", position: "right" },
{ href: "https://play.openpolicyagent.org/", label: "Play", position: "right" },
{
type: "html",
position: "right",
value: `
<a href="https://github.com/open-policy-agent"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub repository">
<img src="${
path.join(baseUrl, "img/nav/github-light.svg")
}" class="light-only" alt="GitHub" style="width: 24px; height: auto; margin-left: 8px;" />
<img src="${
path.join(baseUrl, "img/nav/github-dark.svg")
}" class="dark-only" alt="GitHub" style="width: 24px; height: auto; margin-left: 8px;" />
</a>
`,
},
{
type: "html",
position: "right",
value: `
<a href="https://slack.openpolicyagent.org/"
target="_blank"
rel="noopener noreferrer"
aria-label="Slack community">
<img src="${
path.join(baseUrl, "img/nav/slack-light.svg")
}" class="light-only" alt="Slack" style="width: 24px; height: auto; margin-left: 8px;" />
<img src="${
path.join(baseUrl, "img/nav/slack-dark.svg")
}" class="dark-only" alt="Slack" style="width: 24px; height: auto; margin-left: 8px;" />
</a>
`,
},
],
},
footer: {
style: "light",
links: [],
copyright:
`Open Policy Agent is a <a href="https://www.cncf.io/">Cloud Native Computing Foundation</a> Graduated project.
<img src="${
path.join(baseUrl, "img/footer/cncf-light.svg")
}" alt="CNCF Logo" class="light-only" style="max-width: 10rem; vertical-align: middle; margin: 0 10px;">
<img src="${
path.join(baseUrl, "img/footer/cncf-dark.svg")
}" alt="CNCF Logo" class="dark-only" style="max-width: 10rem; vertical-align: middle; margin: 0 10px;">
<br />
© ${new Date().getFullYear()}
Open Policy Agent contributors.
<a href="https://github.com/open-policy-agent/opa/blob/main/LICENSE">Licensed under the Apache License, Version 2.0</a>.
See the <a href="${
path.join(baseUrl, "/docs/contributing")
}">contributing documentation</a> for information about contributing.
The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, please see our Trademark Usage page.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
additionalLanguages: [
"rego",
"hcl",
"json",
"java",
"scala",
"gradle",
"javadoc",
"sql",
"http",
"diff",
"typescript",
"ini",
"cypher",
"csharp",
"shell-session",
"go-module",
"docker",
"javastacktrace",
"properties",
"log",
],
magicComments: [
{
className: "code-block-terminal-command",
line: "terminal-command",
},
{
className: "code-block-terminal-command",
line: "cmd",
},
{
className: "code-block-diff-add-line",
line: "diff-add",
block: { start: "diff-add-start", end: "diff-add-end" },
},
{
className: "code-block-diff-remove-line",
line: "diff-remove",
block: { start: "diff-remove-start", end: "diff-remove-end" },
},
{
className: "theme-code-block-highlighted-line",
line: "highlight-next-line",
block: { start: "highlight-start", end: "highlight-end" },
},
{
className: "code-block-error-line",
line: "error-next-line",
block: { start: "error-start", end: "error-end" },
},
],
},
mermaid: {
theme: { light: "base", dark: "dark" },
options: {
themeVariables: { // https://mermaid.js.org/config/theming.html#theme-variables
fontFamily: "sans-serif",
primaryColor: "#76d3ed",
secondaryColor: "#fff",
tertiaryColor: "#fff",
},
},
},
},
plugins: [
[
"@docusaurus/plugin-google-gtag",
{
trackingID: "G-JNBNV64PDX",
anonymizeIP: true,
},
],
[
"@docusaurus/plugin-content-docs",
{
id: "regal",
path: "projects/regal",
routeBasePath: "projects/regal",
sidebarPath: require.resolve("./src/lib/sidebar-auto.js"),
},
],
() => ({
name: "raw-loader",
configureWebpack() {
return {
module: {
rules: [
{ test: /\.rego$/, use: "raw-loader" },
{ test: /\.mermaid$/, use: "raw-loader" },
{ test: /\.txt$/, use: "raw-loader" },
],
},
};
},
}),
async function ecosystemLanguagePageGen(context, _options) {
return {
name: "ecosystem-language-gen",
async loadContent() {
const languages = await loadPages(path.join(context.siteDir, "src/data/ecosystem/languages/*.md"));
return { languages };
},
async contentLoaded({ content, actions }) {
const { languages } = content;
await Promise.all(
Object.keys(languages).map(async (language) => {
const routePath = path.join(baseUrl, `/ecosystem/by-language/${language}`);
return actions.addRoute({
path: routePath,
component: require.resolve("./src/EcosystemLanguage.jsx"),
exact: true,
modules: {},
customData: { language },
});
}),
);
},
};
},
async function ecosystemFeaturePageGen(context, _options) {
return {
name: "ecosystem-feature-gen",
async loadContent() {
const features = await loadPages(path.join(context.siteDir, "src/data/ecosystem/features/*.md"));
return { features };
},
async contentLoaded({ content, actions }) {
const { features } = content;
await Promise.all(
Object.keys(features).map(async (feature) => {
const routePath = path.join(baseUrl, `/ecosystem/by-feature/${feature}`);
return actions.addRoute({
path: routePath,
component: require.resolve("./src/EcosystemFeature.jsx"),
exact: true,
modules: {},
customData: { feature },
});
}),
);
},
};
},
async function ecosystemData(context, _options) {
return {
name: "ecosystem-data",
async loadContent() {
const entries = await loadPages(path.join(context.siteDir, "src/data/ecosystem/entries/*.md"));
const languages = await loadPages(path.join(context.siteDir, "src/data/ecosystem/languages/*.md"));
const features = await loadPages(path.join(context.siteDir, "src/data/ecosystem/features/*.md"));
const featureCategories = await loadPages(
path.join(context.siteDir, "src/data/ecosystem/feature-categories/*.md"),
);
return {
entries,
languages,
features,
featureCategories,
};
},
async contentLoaded({ content, actions }) {
const { createData } = actions;
const { entries, languages, features, featureCategories } = content;
await createData("entries.json", JSON.stringify(entries, null, 2));
await createData("languages.json", JSON.stringify(languages, null, 2));
await createData("features.json", JSON.stringify(features, null, 2));
await createData("feature-categories.json", JSON.stringify(featureCategories, null, 2));
},
};
},
async function builtinData(_context, _options) {
return {
name: "builtin-data",
async loadContent() {
const filePath = "../builtin_metadata.json";
const fileContent = await fs.readFile(filePath, "utf-8");
const builtins = JSON.parse(fileContent);
return { builtins };
},
async contentLoaded({ content, actions }) {
const { createData } = actions;
const { builtins } = content;
await createData("builtins.json", JSON.stringify(builtins, null, 2));
},
};
},
async function ecosystemPagesGen(context, _options) {
return {
name: "ecosystem-entries-pages-gen",
async loadContent() {
const entries = await loadPages(path.join(context.siteDir, "src/data/ecosystem/entries/*.md"));
return { entries };
},
async contentLoaded({ content, actions }) {
const { entries } = content;
await Promise.all(
Object.values(entries).map(async (entry) => {
const routePath = path.join(baseUrl, `/ecosystem/entry/${entry.id}`);
return actions.addRoute({
path: routePath,
component: require.resolve("./src/EcosystemEntry.jsx"),
exact: true,
modules: {},
customData: { id: entry.id },
});
}),
);
},
};
},
async function eventsData(context, _options) {
return {
name: "events-data",
async loadContent() {
const events = await loadEvents(path.join(context.siteDir, "src/data/events/*.json"));
return { events };
},
async contentLoaded({ content, actions }) {
const { createData } = actions;
const { events } = content;
await createData("events.json", JSON.stringify(events, null, 2));
},
};
},
async function eventsPagesGen(context, _options) {
return {
name: "events-pages-gen",
async loadContent() {
const events = await loadEvents(path.join(context.siteDir, "src/data/events/*.json"));
return { events };
},
async contentLoaded({ content, actions }) {
const { events } = content;
await Promise.all(
Object.values(events).map(async (event) => {
const routePath = path.join(baseUrl, `/events/${event.id}`);
return actions.addRoute({
path: routePath,
component: require.resolve("./src/EventPage.jsx"),
exact: true,
modules: {},
customData: { id: event.id },
});
}),
);
},
};
},
async function versionsData(context, _options) {
return {
name: "versions-data",
async loadContent() {
const capabilitiesDir = path.resolve(__dirname, "../capabilities");
const dirents = await fs.readdir(capabilitiesDir, { withFileTypes: true });
const versionStrings = dirents
.filter(dirent => dirent.isFile() && dirent.name.endsWith(".json"))
.map(dirent => dirent.name.replace(".json", ""));
const validVersions = versionStrings.filter(v => semver.valid(v));
const sortedVersions = semver.sort(validVersions);
return { versions: sortedVersions };
},
async contentLoaded({ content, actions }) {
const { createData } = actions;
const { versions } = content;
await createData("versions.json", JSON.stringify(versions, null, 2));
const staticDir = path.join(context.siteDir, "static", "data");
await fs.mkdir(staticDir, { recursive: true });
await fs.writeFile(
path.join(staticDir, "versions.json"),
JSON.stringify(versions, null, 2),
);
},
};
},
async function cliData(context, _options) {
return {
name: "cli-data",
async loadContent() {
const filePath = path.join(context.siteDir, "src/data/cli.json");
const cliJson = await fs.readFile(filePath, "utf-8");
const parsedData = JSON.parse(cliJson);
return parsedData;
},
async contentLoaded({ content, actions }) {
const { createData } = actions;
await createData("cli.json", JSON.stringify(content, null, 2));
},
};
},
async function versionsPageGen(_context, _options) {
return {
name: "version-page-gen",
async contentLoaded({ content: _content, actions }) {
return actions.addRoute({
path: path.join(baseUrl, `/docs/archive`),
component: require.resolve("./src/Archive.jsx"),
exact: true,
modules: {},
});
},
};
},
async function regalRulesData() {
return {
name: "regal",
async loadContent() {
const rules = await loadRules();
return { rules };
},
async contentLoaded({ content, actions }) {
await actions.createData("rules.json", JSON.stringify(content.rules, null, 2));
},
};
},
async function surveyData(context, _options) {
return {
name: "survey-data",
async loadContent() {
const eventData = await loadSurveyEventData(
path.join(context.siteDir, "src/data/surveys/events/**/**/data.json"),
);
const questions = await loadSurveyQuestions(
path.join(context.siteDir, "src/data/surveys/questions/**/data.json"),
);
const eventMetadata = await loadSurveyEventMetadata(
path.join(context.siteDir, "src/data/surveys/events/**/metadata.json"),
);
return { eventData, questions, eventMetadata };
},
async contentLoaded({ content, actions }) {
const { createData, addRoute } = actions;
const { eventData, questions, eventMetadata } = content;
await createData("survey-event-data.json", JSON.stringify(eventData, null, 2));
await createData("survey-questions.json", JSON.stringify(questions, null, 2));
await createData("survey-event-metadata.json", JSON.stringify(eventMetadata, null, 2));
// Create a page for each event
const eventSlugs = Object.keys(eventData);
await Promise.all(
eventSlugs.map(async (eventSlug) => {
const routePath = path.join(baseUrl, `/survey/${eventSlug}`);
return addRoute({
path: routePath,
component: require.resolve("./src/SurveyEvent/index.jsx"),
exact: true,
modules: {},
customData: { eventSlug },
});
}),
);
},
};
},
async function glossaryData(context) {
return {
name: "glossary-data",
async loadContent() {
const glossaryPath = path.join(context.siteDir, "glossary.yaml");
const fileContent = await fs.readFile(glossaryPath, "utf-8");
const glossary = yaml.load(fileContent);
return { glossary };
},
async contentLoaded({ content, actions }) {
await actions.createData("glossary.json", JSON.stringify(content.glossary, null, 2));
},
};
},
async function irPlanSchema(context) {
return {
name: "ir-plan-schema",
async loadContent() {
const sourcePath = path.resolve(__dirname, "../v1/ir/plan.schema.json");
const targetDir = path.join(context.siteDir, "static/schemas/ir/v1");
await fs.mkdir(targetDir, { recursive: true });
await fs.copyFile(sourcePath, path.join(targetDir, "plan.schema.json"));
},
};
},
async function bundleManifestSchema(context) {
return {
name: "bundle-manifest-schema",
async loadContent() {
const sourcePath = path.resolve(__dirname, "../v1/bundle/manifest.schema.json");
const targetDir = path.join(context.siteDir, "static/schemas/bundle/v1");
await fs.mkdir(targetDir, { recursive: true });
await fs.copyFile(sourcePath, path.join(targetDir, "manifest.schema.json"));
},
};
},
markdownExportPlugin,
],
clientModules: [
require.resolve("./src/lib/playground.js"),
require.resolve("./src/lib/kapa.js"),
],
stylesheets: [
{
href: "https://unpkg.com/@antonz/codapi@0.19.8/dist/snippet.css",
},
],
scripts: [
{
src: "https://unpkg.com/@antonz/codapi@0.19.8/dist/snippet.js",
defer: true,
},
{
src: "https://widget.kapa.ai/kapa-widget.bundle.js",
"data-website-id": "5c4af137-a024-4ba2-9488-826f1055852c",
"data-project-name": "Open Policy Agent",
"data-project-logo": "https://openpolicyagent.org/img/nav/logo.png",
"data-search-mode-enabled": "true",
// Source UUIDs come from https://app.kapa.ai/422cffb8-2750-48c9-9659-7e8d40b9d5d2/sources
"data-search-source-ids-include":
"f9c26922-8a4c-4a3c-913d-08c2a53a1011,e9daf266-5a9f-410f-8069-18a57dcfb6ee,723b2ac1-807a-43c1-a2aa-bcf8311d2354,fff41a96-7ebe-4fc5-bb60-359e5d830a87,799aac5c-a157-4734-9785-9c754c7c40a0",
"data-modal-open-on-command-k": "true",
"data-modal-command-k-search-mode-default": "true",
"data-deep-thinking-button-hover-background-color": "#f1f8f1",
"data-deep-thinking-button-hover-color": "#2e7d32",
"data-deep-thinking-button-enabled-background-color": "#e8f5e9",
"data-deep-thinking-button-enabled-color": "#2e7d32",
"data-deep-thinking-button-enabled-hover-background-color": "#c8e6c9",
"data-deep-thinking-button-enabled-hover-color": "#1b5e20",
"data-deep-thinking-button-hover-background-color-dark": "#1e3320",
"data-deep-thinking-button-hover-color-dark": "#81c784",
"data-deep-thinking-button-enabled-background-color-dark": "#1a3d1c",
"data-deep-thinking-button-enabled-color-dark": "#a5d6a7",
"data-deep-thinking-button-enabled-hover-background-color-dark": "#245427",
"data-deep-thinking-button-enabled-hover-color-dark": "#c8e6c9",
"data-modal-title": "OPA Chat and Search",
"data-color-scheme-selector": "[data-theme='dark']",
async: true,
},
],
}
);