mirror of
https://github.com/coder/coder.git
synced 2026-10-16 06:37:58 +08:00
fix(offlinedocs): render GitHub markdown alerts (#28822)
> 🤖 This PR was modified by Coder Agents on behalf of Jake Howell.
Ports the GitHub Markdown alert transformer and styling from
`coder/coder.com` into the Next.js `offlinedocs` app so note, tip,
important, warning, and caution blocks render consistently.
Moves HTML sanitization into the rehype pipeline so Markdown blockquotes
and supported raw HTML are parsed before sanitization.
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Adapted from rehype-github-alert.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) Titus Wormer <tituswormer@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* @see {@link https://github.com/rehypejs/rehype-github/tree/main/packages/alert}
|
||||
*/
|
||||
|
||||
import type { Root } from "hast";
|
||||
import { whitespace } from "hast-util-whitespace";
|
||||
import { visit } from "unist-util-visit";
|
||||
|
||||
interface Icon {
|
||||
d: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
const icons: Map<string, Icon> = new Map();
|
||||
|
||||
const TABS_CLASSNAME = "tabs";
|
||||
|
||||
icons.set("caution", {
|
||||
d: "M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z",
|
||||
name: "octicon-stop",
|
||||
});
|
||||
icons.set("important", {
|
||||
d: "M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z",
|
||||
name: "octicon-report",
|
||||
});
|
||||
icons.set("note", {
|
||||
d: "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z",
|
||||
name: "octicon-info",
|
||||
});
|
||||
icons.set("tip", {
|
||||
d: "M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z",
|
||||
name: "octicon-light-bulb",
|
||||
});
|
||||
icons.set("warning", {
|
||||
d: "M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z",
|
||||
name: "octicon-alert",
|
||||
});
|
||||
|
||||
/**
|
||||
* Plugin to enhance alerts.
|
||||
*
|
||||
* @returns
|
||||
* Transform.
|
||||
*/
|
||||
export default function coderGithubAlert() {
|
||||
return (tree: Root) => {
|
||||
visit(tree, "element", (node, index, parent) => {
|
||||
if (
|
||||
node.tagName !== "blockquote" ||
|
||||
typeof index !== "number" ||
|
||||
!parent
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentClassName =
|
||||
parent.type === "element" ? parent.properties.className : "";
|
||||
const isInTabs = Array.isArray(parentClassName)
|
||||
? parentClassName.includes(TABS_CLASSNAME)
|
||||
: parentClassName === TABS_CLASSNAME;
|
||||
const isInAllowedParent =
|
||||
parent.type === "root" ||
|
||||
parent.tagName === "li" ||
|
||||
parent.tagName === "details" ||
|
||||
isInTabs;
|
||||
|
||||
// Must be a `blockquote` element that is a direct child of the root,
|
||||
// a list item, a details element, or a tabs container.
|
||||
if (!isInAllowedParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Must start with a `<p>`.
|
||||
let headIndex = 0;
|
||||
|
||||
while (
|
||||
headIndex < node.children.length &&
|
||||
whitespace(node.children[headIndex])
|
||||
) {
|
||||
headIndex++;
|
||||
}
|
||||
|
||||
const head = node.children[headIndex];
|
||||
|
||||
// Must start with a `p`.
|
||||
if (!head || head.type !== "element" || head.tagName !== "p") return;
|
||||
|
||||
// Must start with `[!`.
|
||||
const text = head.children[0];
|
||||
if (!text || text.type !== "text" || !text.value.startsWith("[!")) return;
|
||||
|
||||
// Must have `]`.
|
||||
const end = text.value.indexOf("]");
|
||||
if (end === -1) return;
|
||||
|
||||
// Must be a known name between
|
||||
const name = text.value.slice(2, end).toLowerCase();
|
||||
const icon = icons.get(name);
|
||||
if (!icon) return;
|
||||
|
||||
if (end + 1 === text.value.length) {
|
||||
// Has to be a `<br>`.
|
||||
const next = head.children[1];
|
||||
|
||||
if (next) {
|
||||
if (next.type !== "element" || next.tagName !== "br") return;
|
||||
// No next sibling? Exit too.
|
||||
if (!head.children[2]) return;
|
||||
// Drop the entire `[!note]` text *and* the `<br>`.
|
||||
head.children = head.children.slice(2);
|
||||
// Drop the `\n` that typically (in markdown) follows `<br>`.
|
||||
const node = head.children[0];
|
||||
if (node && node.type === "text" && node.value.charAt(0) === "\n") {
|
||||
node.value = node.value.slice(1);
|
||||
}
|
||||
} else {
|
||||
let skipped = false;
|
||||
|
||||
// Skip past whitespace.
|
||||
while (
|
||||
headIndex + 1 < node.children.length &&
|
||||
whitespace(node.children[headIndex + 1])
|
||||
) {
|
||||
skipped = true;
|
||||
headIndex++;
|
||||
}
|
||||
|
||||
// Exit if there’s no following element.
|
||||
if (
|
||||
headIndex + 1 === node.children.length ||
|
||||
node.children[headIndex + 1].type !== "element"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Without whitespace,
|
||||
// we still want to skip the paragraph to drop the `[!note]`.
|
||||
if (!skipped) headIndex++;
|
||||
}
|
||||
} else if (
|
||||
text.value.charAt(end + 1) === "\n" &&
|
||||
(end + 2 === text.value.length ||
|
||||
!whitespace(text.value.slice(end + 2)))
|
||||
) {
|
||||
// Drop the `[!note]` from the `text`.
|
||||
text.value = text.value.slice(end + 2);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const displayName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
|
||||
parent.children[index] = {
|
||||
type: "element",
|
||||
tagName: "div",
|
||||
properties: { className: ["markdown-alert", `markdown-alert-${name}`] },
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "p",
|
||||
properties: { className: ["markdown-alert-title"] },
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "svg",
|
||||
properties: {
|
||||
className: ["octicon", icon.name],
|
||||
viewBox: "0 0 16 16",
|
||||
version: "1.1",
|
||||
width: "16",
|
||||
height: "16",
|
||||
ariaHidden: "true",
|
||||
},
|
||||
children: [
|
||||
{
|
||||
type: "element",
|
||||
tagName: "path",
|
||||
properties: { d: icon.d },
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ type: "text", value: displayName },
|
||||
],
|
||||
},
|
||||
...node.children.slice(headIndex),
|
||||
],
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
"archiver": "8.0.0",
|
||||
"framer-motion": "^10.18.0",
|
||||
"front-matter": "4.0.2",
|
||||
"hast-util-whitespace": "3.0.0",
|
||||
"lodash": "4.18.1",
|
||||
"next": "15.5.23",
|
||||
"react": "18.3.1",
|
||||
@@ -26,16 +27,17 @@
|
||||
"react-icons": "5.7.0",
|
||||
"react-markdown": "10.1.0",
|
||||
"rehype-raw": "7.0.0",
|
||||
"rehype-sanitize": "6.0.0",
|
||||
"remark-gfm": "4.0.1",
|
||||
"sanitize-html": "2.17.7"
|
||||
"unist-util-visit": "5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.5.10",
|
||||
"@types/hast": "3.0.4",
|
||||
"@types/lodash": "4.17.25",
|
||||
"@types/node": "22.20.1",
|
||||
"@types/react": "18.3.12",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@types/sanitize-html": "2.16.1",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-next": "14.2.35",
|
||||
"typescript": "6.0.3"
|
||||
|
||||
@@ -37,8 +37,12 @@ import { ReactNode } from "react";
|
||||
import { MdMenu } from "react-icons/md";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import rehypeSanitize, {
|
||||
defaultSchema,
|
||||
type Options as RehypeSanitizeOptions,
|
||||
} from "rehype-sanitize";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
import coderGithubAlert from "../lib/coderGithubAlert";
|
||||
|
||||
type FilePath = string;
|
||||
type UrlPath = string;
|
||||
@@ -52,6 +56,17 @@ type Manifest = { versions: string[]; routes: Route[] };
|
||||
type NavItem = { title: string; path: UrlPath; children?: NavItem[] };
|
||||
type Nav = NavItem[];
|
||||
|
||||
const markdownSanitizeSchema: RehypeSanitizeOptions = {
|
||||
...defaultSchema,
|
||||
tagNames: [...(defaultSchema.tagNames ?? []), "small", "video"],
|
||||
attributes: {
|
||||
...defaultSchema.attributes,
|
||||
"*": [...(defaultSchema.attributes?.["*"] ?? []), "className"],
|
||||
source: [...(defaultSchema.attributes?.source ?? []), "src", "type"],
|
||||
video: ["autoPlay", "loop", "playsInline"],
|
||||
},
|
||||
};
|
||||
|
||||
const readContentFile = (filePath: string) => {
|
||||
const baseDir = process.cwd();
|
||||
const docsPath = path.join(baseDir, "..", "docs");
|
||||
@@ -219,8 +234,7 @@ export const getStaticProps: GetStaticProps = (context) => {
|
||||
const { attributes, body } = fm<{ title?: string }>(
|
||||
readContentFile(route.path),
|
||||
);
|
||||
// Serialize MDX to support custom components
|
||||
const content = sanitizeHtml(body);
|
||||
const content = body;
|
||||
const navigation = getNavigation(manifest);
|
||||
const version = manifest.versions[0];
|
||||
|
||||
@@ -414,7 +428,47 @@ const DocsPage: NextPage<{
|
||||
overflowY="auto"
|
||||
>
|
||||
<Box maxW="872">
|
||||
<Box lineHeight="tall">
|
||||
<Box
|
||||
lineHeight="tall"
|
||||
sx={{
|
||||
"& .markdown-alert": {
|
||||
my: 4,
|
||||
p: 5,
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: "var(--markdown-alert-color)",
|
||||
borderRadius: "md",
|
||||
},
|
||||
"& .markdown-alert-title": {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 1,
|
||||
pt: 0,
|
||||
fontWeight: 600,
|
||||
color: "var(--markdown-alert-color)",
|
||||
},
|
||||
"& .markdown-alert > :last-child": { pb: 0 },
|
||||
"& .markdown-alert svg": {
|
||||
fill: "currentColor",
|
||||
flexShrink: 0,
|
||||
},
|
||||
"& .markdown-alert-note": {
|
||||
"--markdown-alert-color": "#0969da",
|
||||
},
|
||||
"& .markdown-alert-tip": {
|
||||
"--markdown-alert-color": "#1a7f37",
|
||||
},
|
||||
"& .markdown-alert-important": {
|
||||
"--markdown-alert-color": "#8250df",
|
||||
},
|
||||
"& .markdown-alert-warning": {
|
||||
"--markdown-alert-color": "#9a6700",
|
||||
},
|
||||
"& .markdown-alert-caution": {
|
||||
"--markdown-alert-color": "#cf222e",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{/* Some docs don't have the title */}
|
||||
<Heading
|
||||
as="h1"
|
||||
@@ -428,7 +482,12 @@ const DocsPage: NextPage<{
|
||||
</Heading>
|
||||
|
||||
<ReactMarkdown
|
||||
rehypePlugins={[rehypeRaw]}
|
||||
rehypePlugins={[
|
||||
rehypeRaw,
|
||||
// Sanitize author HTML before adding trusted alert markup.
|
||||
[rehypeSanitize, markdownSanitizeSchema],
|
||||
coderGithubAlert,
|
||||
]}
|
||||
remarkPlugins={[remarkGfm]}
|
||||
urlTransform={transformLinkUriSource(route.path)}
|
||||
components={{
|
||||
@@ -477,8 +536,8 @@ const DocsPage: NextPage<{
|
||||
height="auto"
|
||||
/>
|
||||
),
|
||||
p: ({ children }) => (
|
||||
<Text pt={2} pb={2}>
|
||||
p: ({ children, className }) => (
|
||||
<Text className={className} pt={2} pb={2}>
|
||||
{children}
|
||||
</Text>
|
||||
),
|
||||
|
||||
Generated
+30
-162
@@ -37,6 +37,9 @@ importers:
|
||||
front-matter:
|
||||
specifier: 4.0.2
|
||||
version: 4.0.2
|
||||
hast-util-whitespace:
|
||||
specifier: 3.0.0
|
||||
version: 3.0.0
|
||||
lodash:
|
||||
specifier: 4.18.1
|
||||
version: 4.18.1
|
||||
@@ -58,16 +61,22 @@ importers:
|
||||
rehype-raw:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0
|
||||
rehype-sanitize:
|
||||
specifier: 6.0.0
|
||||
version: 6.0.0
|
||||
remark-gfm:
|
||||
specifier: 4.0.1
|
||||
version: 4.0.1
|
||||
sanitize-html:
|
||||
specifier: 2.17.7
|
||||
version: 2.17.7
|
||||
unist-util-visit:
|
||||
specifier: 5.0.0
|
||||
version: 5.0.0
|
||||
devDependencies:
|
||||
'@biomejs/biome':
|
||||
specifier: 2.5.10
|
||||
version: 2.5.10
|
||||
'@types/hast':
|
||||
specifier: 3.0.4
|
||||
version: 3.0.4
|
||||
'@types/lodash':
|
||||
specifier: 4.17.25
|
||||
version: 4.17.25
|
||||
@@ -80,9 +89,6 @@ importers:
|
||||
'@types/react-dom':
|
||||
specifier: 18.3.1
|
||||
version: 18.3.1
|
||||
'@types/sanitize-html':
|
||||
specifier: 2.16.1
|
||||
version: 2.16.1
|
||||
eslint:
|
||||
specifier: 8.57.1
|
||||
version: 8.57.1
|
||||
@@ -621,9 +627,6 @@ packages:
|
||||
'@types/estree@1.0.8':
|
||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||
|
||||
'@types/hast@3.0.3':
|
||||
resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==}
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
|
||||
@@ -657,9 +660,6 @@ packages:
|
||||
'@types/react@18.3.12':
|
||||
resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==}
|
||||
|
||||
'@types/sanitize-html@2.16.1':
|
||||
resolution: {integrity: sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==}
|
||||
|
||||
'@types/unist@2.0.11':
|
||||
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
|
||||
|
||||
@@ -1091,9 +1091,6 @@ packages:
|
||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
dayjs@1.11.23:
|
||||
resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==}
|
||||
|
||||
debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
@@ -1126,10 +1123,6 @@ packages:
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
deepmerge@4.3.1:
|
||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
define-data-property@1.1.4:
|
||||
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1160,35 +1153,6 @@ packages:
|
||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
dom-serializer@2.0.0:
|
||||
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
|
||||
|
||||
dom-serializer@3.1.1:
|
||||
resolution: {integrity: sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
|
||||
domelementtype@3.0.0:
|
||||
resolution: {integrity: sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
domhandler@5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
domhandler@6.0.1:
|
||||
resolution: {integrity: sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
domutils@3.2.2:
|
||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||
|
||||
domutils@4.0.2:
|
||||
resolution: {integrity: sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1206,14 +1170,6 @@ packages:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
entities@7.0.1:
|
||||
resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
entities@8.0.0:
|
||||
resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
error-ex@1.3.4:
|
||||
resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
|
||||
|
||||
@@ -1559,6 +1515,9 @@ packages:
|
||||
hast-util-raw@9.0.1:
|
||||
resolution: {integrity: sha512-5m1gmba658Q+lO5uqL5YNGQWeh1MYWZbZmWrM5lncdcuiXuo5E2HT/CIOp0rLF8ksfSwiCVJ3twlgVRyTGThGA==}
|
||||
|
||||
hast-util-sanitize@5.0.2:
|
||||
resolution: {integrity: sha512-3yTWghByc50aGS7JlGhk61SPenfE/p1oaFeNwkOOyrscaOkMGrcW9+Cy/QAIOBpZxP1yqDIzFMR0+Np0i0+usg==}
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==}
|
||||
|
||||
@@ -1580,13 +1539,6 @@ packages:
|
||||
html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
|
||||
htmlparser2@10.1.0:
|
||||
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
|
||||
|
||||
htmlparser2@12.0.0:
|
||||
resolution: {integrity: sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==}
|
||||
engines: {node: '>=20.19.0'}
|
||||
|
||||
ieee754@1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
|
||||
@@ -1714,10 +1666,6 @@ packages:
|
||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-plain-object@5.1.0:
|
||||
resolution: {integrity: sha512-bUi/yjmtKYcRVUtWRGr0UA6xEFh2I6zWUwMrUXB3s7bmYCaZ8a+0ZsTRkrawh/mzlSD1Y0Ph8bp/U+TvBpWDNw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-regex@1.2.1:
|
||||
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -1816,9 +1764,6 @@ packages:
|
||||
resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==}
|
||||
engines: {node: '>=0.10'}
|
||||
|
||||
launder@1.7.1:
|
||||
resolution: {integrity: sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==}
|
||||
|
||||
lazystream@1.0.1:
|
||||
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
|
||||
engines: {node: '>= 0.6.3'}
|
||||
@@ -2113,9 +2058,6 @@ packages:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
parse-srcset@1.0.2:
|
||||
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||
|
||||
parse5@7.1.2:
|
||||
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
|
||||
|
||||
@@ -2282,6 +2224,9 @@ packages:
|
||||
rehype-raw@7.0.0:
|
||||
resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==}
|
||||
|
||||
rehype-sanitize@6.0.0:
|
||||
resolution: {integrity: sha512-CsnhKNsyI8Tub6L4sm5ZFsme4puGfc6pYylvXo1AeqaGbjOYyzNv3qZPwvs0oMJ39eryyeOdmxwUIo94IpEhqg==}
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==}
|
||||
|
||||
@@ -2341,10 +2286,6 @@ packages:
|
||||
resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
sanitize-html@2.17.7:
|
||||
resolution: {integrity: sha512-PGtEkc9cbnedU3s9TmzDbpsZ8w086g/0Q8k8/oIO1NLNU3i5k9yn835CrjJSajp1KMmkisbO1qPXxNKO3welAg==}
|
||||
engines: {node: '>=22.12.0'}
|
||||
|
||||
scheduler@0.23.2:
|
||||
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
|
||||
|
||||
@@ -3205,10 +3146,6 @@ snapshots:
|
||||
|
||||
'@types/estree@1.0.8': {}
|
||||
|
||||
'@types/hast@3.0.3':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.2
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
@@ -3244,10 +3181,6 @@ snapshots:
|
||||
'@types/prop-types': 15.7.13
|
||||
csstype: 3.1.3
|
||||
|
||||
'@types/sanitize-html@2.16.1':
|
||||
dependencies:
|
||||
htmlparser2: 10.1.0
|
||||
|
||||
'@types/unist@2.0.11': {}
|
||||
|
||||
'@types/unist@3.0.2': {}
|
||||
@@ -3692,8 +3625,6 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
dayjs@1.11.23: {}
|
||||
|
||||
debug@3.2.7:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@@ -3712,8 +3643,6 @@ snapshots:
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
define-data-property@1.1.4:
|
||||
dependencies:
|
||||
es-define-property: 1.0.1
|
||||
@@ -3745,42 +3674,6 @@ snapshots:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
|
||||
dom-serializer@2.0.0:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.5.0
|
||||
|
||||
dom-serializer@3.1.1:
|
||||
dependencies:
|
||||
domelementtype: 3.0.0
|
||||
domhandler: 6.0.1
|
||||
entities: 8.0.0
|
||||
|
||||
domelementtype@2.3.0: {}
|
||||
|
||||
domelementtype@3.0.0: {}
|
||||
|
||||
domhandler@5.0.3:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
domhandler@6.0.1:
|
||||
dependencies:
|
||||
domelementtype: 3.0.0
|
||||
|
||||
domutils@3.2.2:
|
||||
dependencies:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
|
||||
domutils@4.0.2:
|
||||
dependencies:
|
||||
dom-serializer: 3.1.1
|
||||
domelementtype: 3.0.0
|
||||
domhandler: 6.0.1
|
||||
|
||||
dunder-proto@1.0.1:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
@@ -3795,10 +3688,6 @@ snapshots:
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
entities@7.0.1: {}
|
||||
|
||||
entities@8.0.0: {}
|
||||
|
||||
error-ex@1.3.4:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
@@ -4315,6 +4204,12 @@ snapshots:
|
||||
web-namespaces: 2.0.1
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-sanitize@5.0.2:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@ungap/structured-clone': 1.3.0
|
||||
unist-util-position: 5.0.0
|
||||
|
||||
hast-util-to-jsx-runtime@2.3.6:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
@@ -4365,20 +4260,6 @@ snapshots:
|
||||
|
||||
html-void-elements@3.0.0: {}
|
||||
|
||||
htmlparser2@10.1.0:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.2.2
|
||||
entities: 7.0.1
|
||||
|
||||
htmlparser2@12.0.0:
|
||||
dependencies:
|
||||
domelementtype: 3.0.0
|
||||
domhandler: 6.0.1
|
||||
domutils: 4.0.2
|
||||
entities: 8.0.0
|
||||
|
||||
ieee754@1.2.1: {}
|
||||
|
||||
ignore@5.3.2: {}
|
||||
@@ -4502,8 +4383,6 @@ snapshots:
|
||||
|
||||
is-plain-obj@4.1.0: {}
|
||||
|
||||
is-plain-object@5.1.0: {}
|
||||
|
||||
is-regex@1.2.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.4
|
||||
@@ -4604,10 +4483,6 @@ snapshots:
|
||||
dependencies:
|
||||
language-subtag-registry: 0.3.23
|
||||
|
||||
launder@1.7.1:
|
||||
dependencies:
|
||||
dayjs: 1.11.23
|
||||
|
||||
lazystream@1.0.1:
|
||||
dependencies:
|
||||
readable-stream: 2.3.8
|
||||
@@ -5127,8 +5002,6 @@ snapshots:
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
|
||||
parse-srcset@1.0.2: {}
|
||||
|
||||
parse5@7.1.2:
|
||||
dependencies:
|
||||
entities: 4.5.0
|
||||
@@ -5308,10 +5181,15 @@ snapshots:
|
||||
|
||||
rehype-raw@7.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.3
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-raw: 9.0.1
|
||||
vfile: 6.0.1
|
||||
|
||||
rehype-sanitize@6.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-sanitize: 5.0.2
|
||||
|
||||
remark-gfm@4.0.1:
|
||||
dependencies:
|
||||
'@types/mdast': 4.0.4
|
||||
@@ -5399,16 +5277,6 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-regex: 1.2.1
|
||||
|
||||
sanitize-html@2.17.7:
|
||||
dependencies:
|
||||
deepmerge: 4.3.1
|
||||
escape-string-regexp: 4.0.0
|
||||
htmlparser2: 12.0.0
|
||||
is-plain-object: 5.1.0
|
||||
launder: 1.7.1
|
||||
parse-srcset: 1.0.2
|
||||
postcss: 8.5.10
|
||||
|
||||
scheduler@0.23.2:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
Reference in New Issue
Block a user