diff --git a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx index 645b428affe18..b661148996082 100644 --- a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx +++ b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx @@ -11,7 +11,6 @@ import CodeBox from '#site/components/Common/CodeBox'; import LinkWithArrow from '#site/components/Common/LinkWithArrow'; import Link from '#site/components/Link'; import WithReleaseAlertBox from '#site/components/withReleaseAlertBox'; -import { createSval } from '#site/next.jsx.compiler.mjs'; import { ReleaseContext, ReleasesContext, @@ -19,13 +18,14 @@ import { import type { DownloadSnippet } from '#site/types/download'; import type { ReleaseContextType } from '#site/types/release'; import { INSTALL_METHODS } from '#site/util/download'; +import createInterpreter from '#site/util/interpreter'; // Creates a minimal JavaScript interpreter for parsing the JavaScript code from the snippets // Note: that the code runs inside a sandboxed environment and cannot interact with any code outside of the sandbox // It also does not have access to any Global or Window objects, nor it can execute code on the end-user's browser // It also only allows a return statement for a string and it forces the return value to also be a string and only be used // by Shiki to render the highlighted syntax. Hence XSS attacks or JavaScript injections are not possible. -const interpreter = createSval({}, 'script'); +const interpreter = createInterpreter({}, 'script'); /** * Parses a snippet string using the interpreter with the given release context diff --git a/apps/site/next.mdx.compiler.mjs b/apps/site/mdx/compiler.mjs similarity index 86% rename from apps/site/next.mdx.compiler.mjs rename to apps/site/mdx/compiler.mjs index 987e6c8803c7d..630ba814eb73d 100644 --- a/apps/site/next.mdx.compiler.mjs +++ b/apps/site/mdx/compiler.mjs @@ -4,12 +4,12 @@ import { compile as mdxCompile } from '@mdx-js/mdx'; import { Fragment, jsx, jsxs } from 'react/jsx-runtime'; import { matter } from 'vfile-matter'; -import { createSval } from './next.jsx.compiler.mjs'; -import { REHYPE_PLUGINS, REMARK_PLUGINS } from './next.mdx.plugins.mjs'; -import { createGitHubSlugger } from './util/github'; +import { rehypePlugins, remarkPlugins } from './plugins.mjs'; +import { createGitHubSlugger } from '../util/github'; +import createInterpreter from '../util/interpreter'; // Defines a JSX Fragment and JSX Runtime for the MDX Compiler -export const reactRuntime = { Fragment, jsx, jsxs }; +const reactRuntime = { Fragment, jsx, jsxs }; /** * This is our custom simple MDX Compiler that is used to compile Markdown and MDX @@ -27,7 +27,7 @@ export const reactRuntime = { Fragment, jsx, jsxs }; * readingTime: import('reading-time').ReadTimeResults; * }>} */ -export async function compile( +export default async function compile( source, fileExtension, components = {}, @@ -42,12 +42,12 @@ export async function compile( // Compiles the MDX/Markdown source into a serializable VFile const compiled = await mdxCompile(source, { - rehypePlugins: REHYPE_PLUGINS, - remarkPlugins: REMARK_PLUGINS, + rehypePlugins, + remarkPlugins, format: fileExtension, }); - const interpreter = createSval({ + const interpreter = createInterpreter({ ...components, 'react/jsx-runtime': reactRuntime, }); diff --git a/apps/site/mdx/components.mjs b/apps/site/mdx/components.mjs new file mode 100644 index 0000000000000..74fc4074e2e6f --- /dev/null +++ b/apps/site/mdx/components.mjs @@ -0,0 +1,87 @@ +'use strict'; + +import BadgeGroup from '@node-core/ui-components/Common/BadgeGroup'; +import Blockquote from '@node-core/ui-components/Common/Blockquote'; +import MDXCodeTabs from '@node-core/ui-components/MDX/CodeTabs'; + +import Button from '#site/components/Common/Button'; +import LinkWithArrow from '#site/components/Common/LinkWithArrow'; +import DownloadButton from '#site/components/Downloads/DownloadButton'; +import DownloadsTable from '#site/components/Downloads/DownloadsTable'; +import BlogPostLink from '#site/components/Downloads/Release/BlogPostLink'; +import ChangelogLink from '#site/components/Downloads/Release/ChangelogLink'; +import ReleaseDownloadLink from '#site/components/Downloads/Release/DownloadLink'; +import ReleaseInstallationMethodDropdown from '#site/components/Downloads/Release/InstallationMethodDropdown'; +import ReleaseOperatingSystemDropdown from '#site/components/Downloads/Release/OperatingSystemDropdown'; +import ReleasePackageManagerDropdown from '#site/components/Downloads/Release/PackageManagerDropdown'; +import ReleasePlatformDropdown from '#site/components/Downloads/Release/PlatformDropdown'; +import ReleasePrebuiltDownloadButtons from '#site/components/Downloads/Release/PrebuiltDownloadButtons'; +import ReleaseCodeBox from '#site/components/Downloads/Release/ReleaseCodeBox'; +import ReleaseVersionDropdown from '#site/components/Downloads/Release/VersionDropdown'; +import EOLAlertBox from '#site/components/EOL/EOLAlert'; +import EOLReleaseTable from '#site/components/EOL/EOLReleaseTable'; +import Link from '#site/components/Link'; +import UpcomingMeetings from '#site/components/MDX/Calendar/UpcomingMeetings'; +import MDXCodeBox from '#site/components/MDX/CodeBox'; +import MDXImage from '#site/components/MDX/Image'; +import MinorReleasesTable from '#site/components/Releases/MinorReleasesTable'; +import PreviousReleasesTable from '#site/components/Releases/PreviousReleasesTable'; +import ReleaseOverview from '#site/components/Releases/ReleaseOverview'; +import WithBadgeGroup from '#site/components/withBadgeGroup'; +import WithBanner from '#site/components/withBanner'; +import WithDownloadArchive from '#site/components/withDownloadArchive'; +import WithNodeRelease from '#site/components/withNodeRelease'; +import WithReleaseAlertBox from '#site/components/withReleaseAlertBox'; +import WithReleaseSelect from '#site/components/withReleaseSelect'; +import { ReleaseProvider } from '#site/providers/releaseProvider'; + +/** + * A full list of React Components that we want to pass through to MDX + * + * @satisfies {import('mdx/types').MDXComponents} + */ +export default { + // HTML overrides + a: Link, + blockquote: Blockquote, + pre: MDXCodeBox, + img: MDXImage, + // Renders MDX CodeTabs + CodeTabs: MDXCodeTabs, + // Renders a Download Button + DownloadButton, + // Renders a stateless Release Select Component + WithReleaseSelect, + // Group of components that enable you to select versions for Node.js + // releases and download selected versions. Uses `releaseProvider` as a provider + Release: { + Provider: ReleaseProvider, + VersionDropdown: ReleaseVersionDropdown, + InstallationMethodDropdown: ReleaseInstallationMethodDropdown, + PackageManagerDropdown: ReleasePackageManagerDropdown, + PlatformDropdown: ReleasePlatformDropdown, + OperatingSystemDropdown: ReleaseOperatingSystemDropdown, + BlogPostLink, + PrebuiltDownloadButtons: ReleasePrebuiltDownloadButtons, + ReleaseCodeBox, + ChangelogLink, + DownloadLink: ReleaseDownloadLink, + }, + // HOC for providing the Download Archive Page properties + WithDownloadArchive, + DownloadsTable, + PreviousReleasesTable, + WithNodeRelease, + WithReleaseAlertBox, + WithBanner, + WithBadgeGroup, + BadgeGroup, + ReleaseOverview, + MinorReleasesTable, + UpcomingMeetings, + EOLAlertBox, + EOLReleaseTable, + Button, + Link, + LinkWithArrow, +}; diff --git a/apps/site/next.mdx.plugins.mjs b/apps/site/mdx/plugins.mjs similarity index 89% rename from apps/site/next.mdx.plugins.mjs rename to apps/site/mdx/plugins.mjs index 76a8cd777982b..b985d40d1655a 100644 --- a/apps/site/next.mdx.plugins.mjs +++ b/apps/site/mdx/plugins.mjs @@ -7,12 +7,12 @@ import rehypeSlug from 'rehype-slug'; import remarkGfm from 'remark-gfm'; import readingTime from 'remark-reading-time'; -import remarkTableTitles from './util/table'; +import remarkTableTitles from '../util/table'; /** * Provides all our Rehype Plugins that are used within MDX */ -export const REHYPE_PLUGINS = [ +export const rehypePlugins = [ // Generates `id` attributes for headings (H1, ...) rehypeSlug, // Automatically add anchor links to headings (H1, ...) @@ -25,7 +25,7 @@ export const REHYPE_PLUGINS = [ /** * Provides all our Remark Plugins that are used within MDX */ -export const REMARK_PLUGINS = [ +export const remarkPlugins = [ // Support GFM syntax to be used within Markdown remarkGfm, // Generates metadata regarding headings diff --git a/apps/site/next.dynamic.mjs b/apps/site/next.dynamic.mjs index 8ef4a268bc803..41c49be14d48d 100644 --- a/apps/site/next.dynamic.mjs +++ b/apps/site/next.dynamic.mjs @@ -7,6 +7,8 @@ import matter from 'gray-matter'; import { cache } from 'react'; import { VFile } from 'vfile'; +import compile from './mdx/compiler.mjs'; +import mdxComponents from './mdx/components.mjs'; import { BASE_PATH } from './next.constants.mjs'; import { BASE_URL } from './next.constants.mjs'; import { DEFAULT_CATEGORY_OG_TYPE } from './next.constants.mjs'; @@ -16,8 +18,6 @@ import { PAGE_METADATA } from './next.dynamic.constants.mjs'; import { getMarkdownFiles } from './next.helpers.mjs'; import { siteConfig } from './next.json.mjs'; import { availableLocaleCodes, defaultLocale } from './next.locales.mjs'; -import { compile } from './next.mdx.compiler.mjs'; -import { MDX_COMPONENTS } from './next.mdx.components.mjs'; // This is the combination of the Application Base URL and Base PATH const baseUrlAndPath = `${BASE_URL}${BASE_PATH}`; @@ -177,7 +177,7 @@ const getDynamicRouter = async () => { // This compiles our MDX source (VFile) into a final MDX-parsed VFile // that then is passed as a string to the MDXProvider which will run the MDX Code - return compile(sourceAsVirtualFile, fileExtension, MDX_COMPONENTS); + return compile(sourceAsVirtualFile, fileExtension, mdxComponents); }; // Creates a Cached Version of the MDX Compiler diff --git a/apps/site/next.jsx.compiler.mjs b/apps/site/next.jsx.compiler.mjs deleted file mode 100644 index f536b14e84502..0000000000000 --- a/apps/site/next.jsx.compiler.mjs +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import Sval from 'sval'; - -/** - * Creates a JavaScript Evaluater - * - * @param {Record} dependencies All sort of dependencies to be passed to the JavaScript context - * @param {'module' | 'script'} mode The mode of the JavaScript execution - * - * @returns {Sval} Returns an Sandboxed instance of a JavaScript interpreter - */ -export const createSval = (dependencies = {}, mode = 'module') => { - const svalInterpreter = new Sval({ - ecmaVer: 'latest', - sandBox: true, - sourceType: mode, - }); - - svalInterpreter.import(dependencies); - - return svalInterpreter; -}; diff --git a/apps/site/next.mdx.components.mjs b/apps/site/next.mdx.components.mjs deleted file mode 100644 index c7a55cfc90d6f..0000000000000 --- a/apps/site/next.mdx.components.mjs +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -import { htmlComponents, clientMdxComponents } from './next.mdx.use.client.mjs'; -import { mdxComponents } from './next.mdx.use.mjs'; - -/** - * Combine all MDX Components to be used - * - * @type {import('mdx/types').MDXComponents} - */ -export const MDX_COMPONENTS = { - ...htmlComponents, - ...clientMdxComponents, - ...mdxComponents, -}; diff --git a/apps/site/next.mdx.use.client.mjs b/apps/site/next.mdx.use.client.mjs deleted file mode 100644 index e0a22055a01ec..0000000000000 --- a/apps/site/next.mdx.use.client.mjs +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -import Blockquote from '@node-core/ui-components/Common/Blockquote'; -import MDXCodeTabs from '@node-core/ui-components/MDX/CodeTabs'; - -import DownloadButton from './components/Downloads/DownloadButton'; -import BlogPostLink from './components/Downloads/Release/BlogPostLink'; -import ChangelogLink from './components/Downloads/Release/ChangelogLink'; -import ReleaseDownloadLink from './components/Downloads/Release/DownloadLink'; -import ReleaseInstallationMethodDropdown from './components/Downloads/Release/InstallationMethodDropdown'; -import ReleaseOperatingSystemDropdown from './components/Downloads/Release/OperatingSystemDropdown'; -import ReleasePackageManagerDropdown from './components/Downloads/Release/PackageManagerDropdown'; -import ReleasePlatformDropdown from './components/Downloads/Release/PlatformDropdown'; -import ReleasePrebuiltDownloadButtons from './components/Downloads/Release/PrebuiltDownloadButtons'; -import ReleaseCodeBox from './components/Downloads/Release/ReleaseCodeBox'; -import ReleaseVersionDropdown from './components/Downloads/Release/VersionDropdown'; -import Link from './components/Link'; -import MDXCodeBox from './components/MDX/CodeBox'; -import MDXImage from './components/MDX/Image'; -import WithReleaseSelect from './components/withReleaseSelect'; -import { ReleaseProvider } from './providers/releaseProvider'; - -/** - * A full list of React Components that we want to pass through to MDX - * - * @satisfies {import('mdx/types').MDXComponents} - */ -export const clientMdxComponents = { - // Renders MDX CodeTabs - CodeTabs: MDXCodeTabs, - // Renders a Download Button - DownloadButton, - // Renders a stateless Release Select Component - WithReleaseSelect, - // Group of components that enable you to select versions for Node.js - // releases and download selected versions. Uses `releaseProvider` as a provider - Release: { - // Provides an individual Node.js Release Context for Downloads - Provider: ReleaseProvider, - // Renders a drop-down menu to select a version - VersionDropdown: ReleaseVersionDropdown, - // Renders a drop-down menu to select a platform - InstallationMethodDropdown: ReleaseInstallationMethodDropdown, - // Renders a drop-down menu to select a package manager - PackageManagerDropdown: ReleasePackageManagerDropdown, - // Renders a drop-down menu to select a bitness - PlatformDropdown: ReleasePlatformDropdown, - // Renders a drop-down menu to select an operating system - OperatingSystemDropdown: ReleaseOperatingSystemDropdown, - // Renders a Blog Post Link for the selected release - BlogPostLink, - // Renders a Download Button for the selected release - PrebuiltDownloadButtons: ReleasePrebuiltDownloadButtons, - // Renders a Release CodeBox - ReleaseCodeBox, - // Renders a Changelog Link Button - ChangelogLink, - // Renders a DownloadLink Button - DownloadLink: ReleaseDownloadLink, - }, -}; - -/** - * A full list of wired HTML elements into custom React Components - * - * @type {import('mdx/types').MDXComponents} - */ -export const htmlComponents = { - // Renders a Link Component for `a` tags - a: Link, - // Renders a Blockquote Component for `blockquote` tags - blockquote: Blockquote, - // Renders a CodeBox Component for `pre` tags - pre: MDXCodeBox, - // Renders an Image Component for `img` tags - img: MDXImage, -}; diff --git a/apps/site/next.mdx.use.mjs b/apps/site/next.mdx.use.mjs deleted file mode 100644 index ea294d3b8d6fa..0000000000000 --- a/apps/site/next.mdx.use.mjs +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -import BadgeGroup from '@node-core/ui-components/Common/BadgeGroup'; - -import Button from './components/Common/Button'; -import LinkWithArrow from './components/Common/LinkWithArrow'; -import DownloadsTable from './components/Downloads/DownloadsTable'; -import EOLAlertBox from './components/EOL/EOLAlert'; -import EOLReleaseTable from './components/EOL/EOLReleaseTable'; -import Link from './components/Link'; -import UpcomingMeetings from './components/MDX/Calendar/UpcomingMeetings'; -import MinorReleasesTable from './components/Releases/MinorReleasesTable'; -import PreviousReleasesTable from './components/Releases/PreviousReleasesTable'; -import ReleaseOverview from './components/Releases/ReleaseOverview'; -import WithBadgeGroup from './components/withBadgeGroup'; -import WithBanner from './components/withBanner'; -import WithDownloadArchive from './components/withDownloadArchive'; -import WithNodeRelease from './components/withNodeRelease'; -import WithReleaseAlertBox from './components/withReleaseAlertBox'; - -/** - * A full list of React Components that we want to pass through to MDX - * - * @satisfies {import('mdx/types').MDXComponents} - */ -export const mdxComponents = { - // HOC for providing the Download Archive Page properties - WithDownloadArchive, - // Renders a table with Node.js Releases with different platforms and architectures - DownloadsTable, - PreviousReleasesTable, - // HOC for getting Node.js Release Metadata - WithNodeRelease, - // Renders an alert box with the given release status - WithReleaseAlertBox, - // HOC for providing Banner Data - WithBanner, - // HOC for providing Badge Data - WithBadgeGroup, - // Standalone Badge Group - BadgeGroup, - // Renders the Release Overview for a specified version - ReleaseOverview, - // Renders a table with all the Minor Releases for a Major Version - MinorReleasesTable, - // Renders an container for Upcoming Node.js Meetings - UpcomingMeetings, - // Renders an EOL alert - EOLAlertBox, - // Renders the EOL Table - EOLReleaseTable, - // Renders a Button Component for `button` tags - Button, - // Regular links (without arrow) - Link, - // Links with External Arrow - LinkWithArrow, -}; diff --git a/apps/site/util/interpreter.ts b/apps/site/util/interpreter.ts new file mode 100644 index 0000000000000..caddbc7a79a06 --- /dev/null +++ b/apps/site/util/interpreter.ts @@ -0,0 +1,18 @@ +'use strict'; + +import Sval from 'sval'; + +export default ( + dependencies: Record = {}, + mode: 'module' | 'script' = 'module' +) => { + const svalInterpreter = new Sval({ + ecmaVer: 'latest', + sandBox: true, + sourceType: mode, + }); + + svalInterpreter.import(dependencies); + + return svalInterpreter; +};