From 3dd9eb281c5834418515c575e2b665369cb66103 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Sat, 13 Jun 2026 14:02:59 +0100 Subject: [PATCH 1/4] feat(ipa): Register IPA components in global MDX scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swizzle theme/MDXComponents to add , , , and to Docusaurus' global MDX scope, so guideline documents can use them without an import line in every file. PrincipleHeader is omitted — it is auto-injected from frontmatter by the DocItem/Content swizzle. Add a unit test asserting the components are registered and the original theme components preserved. Aliasing @theme-original/MDXComponents to a stub in vitest.config lets the swizzle be imported under vitest (the alias is build-generated and absent at test time). --- src/theme/MDXComponents.test.tsx | 34 +++++++++++++++++++++ src/theme/MDXComponents.tsx | 20 ++++++++++++ test/stubs/theme-original-mdx-components.ts | 9 ++++++ vitest.config.ts | 8 +++++ 4 files changed, 71 insertions(+) create mode 100644 src/theme/MDXComponents.test.tsx create mode 100644 src/theme/MDXComponents.tsx create mode 100644 test/stubs/theme-original-mdx-components.ts diff --git a/src/theme/MDXComponents.test.tsx b/src/theme/MDXComponents.test.tsx new file mode 100644 index 0000000..35de2dc --- /dev/null +++ b/src/theme/MDXComponents.test.tsx @@ -0,0 +1,34 @@ +import { describe, it, expect, vi } from "vitest"; + +// The IPA components transitively import Docusaurus client modules (the docs +// client via usePrinciple, the site context via Workflow); stub both so the +// barrel resolves under vitest. +vi.mock("@docusaurus/plugin-content-docs/client", () => ({ + useDoc: () => ({ frontMatter: { id: 1, state: "adopt" } }), +})); + +vi.mock("@docusaurus/useDocusaurusContext", () => ({ + default: () => ({ siteConfig: { customFields: {} } }), +})); + +import MDXComponents from "./MDXComponents"; +import { + Guidelines, + Guideline, + Example, + Workflow, +} from "@site/src/components/ipa"; + +describe("theme/MDXComponents", () => { + it("registers the IPA authoring components in global MDX scope", () => { + expect(MDXComponents.Guidelines).toBe(Guidelines); + expect(MDXComponents.Guideline).toBe(Guideline); + expect(MDXComponents.Example).toBe(Example); + expect(MDXComponents.Workflow).toBe(Workflow); + }); + + it("preserves the original theme MDX components", () => { + expect(MDXComponents.code).toBeDefined(); + expect(MDXComponents.a).toBeDefined(); + }); +}); diff --git a/src/theme/MDXComponents.tsx b/src/theme/MDXComponents.tsx new file mode 100644 index 0000000..622bf30 --- /dev/null +++ b/src/theme/MDXComponents.tsx @@ -0,0 +1,20 @@ +import MDXComponents from "@theme-original/MDXComponents"; +import { + Guidelines, + Guideline, + Example, + Workflow, +} from "@site/src/components/ipa"; + +// Register the IPA authoring components in Docusaurus' global MDX scope so +// guideline documents can use , , , and +// without an import in every file. PrincipleHeader is intentionally +// omitted — it is auto-injected from frontmatter by the DocItem/Content +// swizzle, not authored inline. +export default { + ...MDXComponents, + Guidelines, + Guideline, + Example, + Workflow, +}; diff --git a/test/stubs/theme-original-mdx-components.ts b/test/stubs/theme-original-mdx-components.ts new file mode 100644 index 0000000..10f3dde --- /dev/null +++ b/test/stubs/theme-original-mdx-components.ts @@ -0,0 +1,9 @@ +// Stub for Docusaurus' generated `@theme-original/MDXComponents` module, which +// only exists during a real build. Vitest aliases the import here so the +// MDXComponents swizzle can be unit-tested in isolation. Mirrors the shape of +// the real default export (a map of HTML tag -> component) closely enough for +// the swizzle's spread to be exercised. +export default { + code: () => null, + a: () => null, +}; diff --git a/vitest.config.ts b/vitest.config.ts index 286efcc..0da4fc9 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -14,6 +14,14 @@ export default defineConfig({ "@site": fileURLToPath(new URL(".", import.meta.url)), "@docusaurus/useDocusaurusContext": "@docusaurus/core/lib/client/exports/useDocusaurusContext", + // @theme-original/* aliases are generated during a Docusaurus build and + // don't resolve under vitest; point the one our swizzle re-exports at a stub. + "@theme-original/MDXComponents": fileURLToPath( + new URL( + "./test/stubs/theme-original-mdx-components.ts", + import.meta.url, + ), + ), }, }, test: { From db187cfc9b2d9febf3c456ee5aa9fe2e5a60ce19 Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Sat, 13 Jun 2026 17:03:57 +0100 Subject: [PATCH 2/4] fix(ipa): Preserve MDX theme components in global scope --- src/theme/MDXComponents.tsx | 31 +++++++++++++++++++-- test/stubs/mdx-component.ts | 9 ++++++ test/stubs/theme-original-mdx-components.ts | 9 ------ vitest.config.ts | 25 +++++++++++------ 4 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 test/stubs/mdx-component.ts delete mode 100644 test/stubs/theme-original-mdx-components.ts diff --git a/src/theme/MDXComponents.tsx b/src/theme/MDXComponents.tsx index 622bf30..1b2368a 100644 --- a/src/theme/MDXComponents.tsx +++ b/src/theme/MDXComponents.tsx @@ -1,4 +1,15 @@ -import MDXComponents from "@theme-original/MDXComponents"; +import React, { type ComponentProps } from "react"; +import Head from "@docusaurus/Head"; +import Admonition from "@theme/Admonition"; +import Mermaid from "@theme/Mermaid"; +import MDXA from "@theme-original/MDXComponents/A"; +import MDXCode from "@theme-original/MDXComponents/Code"; +import MDXDetails from "@theme-original/MDXComponents/Details"; +import MDXHeading from "@theme-original/MDXComponents/Heading"; +import MDXImg from "@theme-original/MDXComponents/Img"; +import MDXLi from "@theme-original/MDXComponents/Li"; +import MDXPre from "@theme-original/MDXComponents/Pre"; +import MDXUl from "@theme-original/MDXComponents/Ul"; import { Guidelines, Guideline, @@ -12,7 +23,23 @@ import { // omitted — it is auto-injected from frontmatter by the DocItem/Content // swizzle, not authored inline. export default { - ...MDXComponents, + Head, + details: MDXDetails, + Details: MDXDetails, + code: MDXCode, + a: MDXA, + pre: MDXPre, + ul: MDXUl, + li: MDXLi, + img: MDXImg, + h1: (props: ComponentProps<"h1">) => , + h2: (props: ComponentProps<"h2">) => , + h3: (props: ComponentProps<"h3">) => , + h4: (props: ComponentProps<"h4">) => , + h5: (props: ComponentProps<"h5">) => , + h6: (props: ComponentProps<"h6">) => , + admonition: Admonition, + mermaid: Mermaid, Guidelines, Guideline, Example, diff --git a/test/stubs/mdx-component.ts b/test/stubs/mdx-component.ts new file mode 100644 index 0000000..5273967 --- /dev/null +++ b/test/stubs/mdx-component.ts @@ -0,0 +1,9 @@ +import type { ReactNode } from "react"; + +export default function MdxComponentStub({ + children, +}: { + children?: ReactNode; +}) { + return children ?? null; +} diff --git a/test/stubs/theme-original-mdx-components.ts b/test/stubs/theme-original-mdx-components.ts deleted file mode 100644 index 10f3dde..0000000 --- a/test/stubs/theme-original-mdx-components.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Stub for Docusaurus' generated `@theme-original/MDXComponents` module, which -// only exists during a real build. Vitest aliases the import here so the -// MDXComponents swizzle can be unit-tested in isolation. Mirrors the shape of -// the real default export (a map of HTML tag -> component) closely enough for -// the swizzle's spread to be exercised. -export default { - code: () => null, - a: () => null, -}; diff --git a/vitest.config.ts b/vitest.config.ts index 0da4fc9..8ab5219 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,6 +2,10 @@ import { fileURLToPath } from "node:url"; import { defineConfig } from "vitest/config"; import react from "@vitejs/plugin-react"; +const mdxComponentStub = fileURLToPath( + new URL("./test/stubs/mdx-component.ts", import.meta.url), +); + // Docusaurus' tsconfig uses `jsx: preserve` because its build pipeline // transforms JSX downstream. Vitest doesn't run through that pipeline, // so it needs the canonical React + Vite plugin to transform JSX in @@ -14,14 +18,19 @@ export default defineConfig({ "@site": fileURLToPath(new URL(".", import.meta.url)), "@docusaurus/useDocusaurusContext": "@docusaurus/core/lib/client/exports/useDocusaurusContext", - // @theme-original/* aliases are generated during a Docusaurus build and - // don't resolve under vitest; point the one our swizzle re-exports at a stub. - "@theme-original/MDXComponents": fileURLToPath( - new URL( - "./test/stubs/theme-original-mdx-components.ts", - import.meta.url, - ), - ), + // Docusaurus theme aliases are generated during a Docusaurus build and + // don't resolve under vitest; stub the theme components imported by swizzles. + "@docusaurus/Head": mdxComponentStub, + "@theme/Admonition": mdxComponentStub, + "@theme/Mermaid": mdxComponentStub, + "@theme-original/MDXComponents/A": mdxComponentStub, + "@theme-original/MDXComponents/Code": mdxComponentStub, + "@theme-original/MDXComponents/Details": mdxComponentStub, + "@theme-original/MDXComponents/Heading": mdxComponentStub, + "@theme-original/MDXComponents/Img": mdxComponentStub, + "@theme-original/MDXComponents/Li": mdxComponentStub, + "@theme-original/MDXComponents/Pre": mdxComponentStub, + "@theme-original/MDXComponents/Ul": mdxComponentStub, }, }, test: { From 1a1421eca6490f7362c5dd30cc8292302a59599b Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Sun, 14 Jun 2026 00:20:03 +0100 Subject: [PATCH 3/4] test(ipa): Cover MDX globals with fixture --- ipa/dev/component-fixtures.mdx | 7 ------- src/theme/MDXComponents.test.tsx | 34 -------------------------------- test/stubs/mdx-component.ts | 9 --------- vitest.config.ts | 17 ---------------- 4 files changed, 67 deletions(-) delete mode 100644 src/theme/MDXComponents.test.tsx delete mode 100644 test/stubs/mdx-component.ts diff --git a/ipa/dev/component-fixtures.mdx b/ipa/dev/component-fixtures.mdx index adee63a..e94aabe 100644 --- a/ipa/dev/component-fixtures.mdx +++ b/ipa/dev/component-fixtures.mdx @@ -9,13 +9,6 @@ description: production builds." --- -import { - Guidelines, - Guideline, - Example, - Workflow, -} from "@site/src/components/ipa"; - # Component fixtures This page is not shipped — `draft: true` excludes it from production. Each diff --git a/src/theme/MDXComponents.test.tsx b/src/theme/MDXComponents.test.tsx deleted file mode 100644 index 35de2dc..0000000 --- a/src/theme/MDXComponents.test.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { describe, it, expect, vi } from "vitest"; - -// The IPA components transitively import Docusaurus client modules (the docs -// client via usePrinciple, the site context via Workflow); stub both so the -// barrel resolves under vitest. -vi.mock("@docusaurus/plugin-content-docs/client", () => ({ - useDoc: () => ({ frontMatter: { id: 1, state: "adopt" } }), -})); - -vi.mock("@docusaurus/useDocusaurusContext", () => ({ - default: () => ({ siteConfig: { customFields: {} } }), -})); - -import MDXComponents from "./MDXComponents"; -import { - Guidelines, - Guideline, - Example, - Workflow, -} from "@site/src/components/ipa"; - -describe("theme/MDXComponents", () => { - it("registers the IPA authoring components in global MDX scope", () => { - expect(MDXComponents.Guidelines).toBe(Guidelines); - expect(MDXComponents.Guideline).toBe(Guideline); - expect(MDXComponents.Example).toBe(Example); - expect(MDXComponents.Workflow).toBe(Workflow); - }); - - it("preserves the original theme MDX components", () => { - expect(MDXComponents.code).toBeDefined(); - expect(MDXComponents.a).toBeDefined(); - }); -}); diff --git a/test/stubs/mdx-component.ts b/test/stubs/mdx-component.ts deleted file mode 100644 index 5273967..0000000 --- a/test/stubs/mdx-component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { ReactNode } from "react"; - -export default function MdxComponentStub({ - children, -}: { - children?: ReactNode; -}) { - return children ?? null; -} diff --git a/vitest.config.ts b/vitest.config.ts index 8ab5219..286efcc 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,10 +2,6 @@ import { fileURLToPath } from "node:url"; import { defineConfig } from "vitest/config"; import react from "@vitejs/plugin-react"; -const mdxComponentStub = fileURLToPath( - new URL("./test/stubs/mdx-component.ts", import.meta.url), -); - // Docusaurus' tsconfig uses `jsx: preserve` because its build pipeline // transforms JSX downstream. Vitest doesn't run through that pipeline, // so it needs the canonical React + Vite plugin to transform JSX in @@ -18,19 +14,6 @@ export default defineConfig({ "@site": fileURLToPath(new URL(".", import.meta.url)), "@docusaurus/useDocusaurusContext": "@docusaurus/core/lib/client/exports/useDocusaurusContext", - // Docusaurus theme aliases are generated during a Docusaurus build and - // don't resolve under vitest; stub the theme components imported by swizzles. - "@docusaurus/Head": mdxComponentStub, - "@theme/Admonition": mdxComponentStub, - "@theme/Mermaid": mdxComponentStub, - "@theme-original/MDXComponents/A": mdxComponentStub, - "@theme-original/MDXComponents/Code": mdxComponentStub, - "@theme-original/MDXComponents/Details": mdxComponentStub, - "@theme-original/MDXComponents/Heading": mdxComponentStub, - "@theme-original/MDXComponents/Img": mdxComponentStub, - "@theme-original/MDXComponents/Li": mdxComponentStub, - "@theme-original/MDXComponents/Pre": mdxComponentStub, - "@theme-original/MDXComponents/Ul": mdxComponentStub, }, }, test: { From 2ea72bbd7fc7247fafbcb8bc376fc0a0509d652f Mon Sep 17 00:00:00 2001 From: Andrei Matei Date: Sun, 14 Jun 2026 00:30:59 +0100 Subject: [PATCH 4/4] fix(ipa): Wrap MDX components from folder swizzle --- src/theme/MDXComponents.tsx | 47 ------------------------------- src/theme/MDXComponents/index.tsx | 20 +++++++++++++ 2 files changed, 20 insertions(+), 47 deletions(-) delete mode 100644 src/theme/MDXComponents.tsx create mode 100644 src/theme/MDXComponents/index.tsx diff --git a/src/theme/MDXComponents.tsx b/src/theme/MDXComponents.tsx deleted file mode 100644 index 1b2368a..0000000 --- a/src/theme/MDXComponents.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { type ComponentProps } from "react"; -import Head from "@docusaurus/Head"; -import Admonition from "@theme/Admonition"; -import Mermaid from "@theme/Mermaid"; -import MDXA from "@theme-original/MDXComponents/A"; -import MDXCode from "@theme-original/MDXComponents/Code"; -import MDXDetails from "@theme-original/MDXComponents/Details"; -import MDXHeading from "@theme-original/MDXComponents/Heading"; -import MDXImg from "@theme-original/MDXComponents/Img"; -import MDXLi from "@theme-original/MDXComponents/Li"; -import MDXPre from "@theme-original/MDXComponents/Pre"; -import MDXUl from "@theme-original/MDXComponents/Ul"; -import { - Guidelines, - Guideline, - Example, - Workflow, -} from "@site/src/components/ipa"; - -// Register the IPA authoring components in Docusaurus' global MDX scope so -// guideline documents can use , , , and -// without an import in every file. PrincipleHeader is intentionally -// omitted — it is auto-injected from frontmatter by the DocItem/Content -// swizzle, not authored inline. -export default { - Head, - details: MDXDetails, - Details: MDXDetails, - code: MDXCode, - a: MDXA, - pre: MDXPre, - ul: MDXUl, - li: MDXLi, - img: MDXImg, - h1: (props: ComponentProps<"h1">) => , - h2: (props: ComponentProps<"h2">) => , - h3: (props: ComponentProps<"h3">) => , - h4: (props: ComponentProps<"h4">) => , - h5: (props: ComponentProps<"h5">) => , - h6: (props: ComponentProps<"h6">) => , - admonition: Admonition, - mermaid: Mermaid, - Guidelines, - Guideline, - Example, - Workflow, -}; diff --git a/src/theme/MDXComponents/index.tsx b/src/theme/MDXComponents/index.tsx new file mode 100644 index 0000000..622bf30 --- /dev/null +++ b/src/theme/MDXComponents/index.tsx @@ -0,0 +1,20 @@ +import MDXComponents from "@theme-original/MDXComponents"; +import { + Guidelines, + Guideline, + Example, + Workflow, +} from "@site/src/components/ipa"; + +// Register the IPA authoring components in Docusaurus' global MDX scope so +// guideline documents can use , , , and +// without an import in every file. PrincipleHeader is intentionally +// omitted — it is auto-injected from frontmatter by the DocItem/Content +// swizzle, not authored inline. +export default { + ...MDXComponents, + Guidelines, + Guideline, + Example, + Workflow, +};