diff --git a/.gitignore b/.gitignore index a29a73c4f8f23..7c590f048bd13 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +# Ignore generated export markdown files +/public/md-exports/ + # Runtime data pids *.pid diff --git a/next.config.ts b/next.config.ts index cf57e2050208f..56fb66502edf1 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import {codecovNextJSWebpackPlugin} from '@codecov/nextjs-webpack-plugin'; import {withSentryConfig} from '@sentry/nextjs'; -import {redirects} from './redirects'; +import {redirects} from './redirects.js'; const outputFileTracingExcludes = process.env.NEXT_PUBLIC_DEVELOPER_DOCS ? { @@ -55,6 +55,12 @@ const nextConfig = { DEVELOPER_DOCS_: process.env.NEXT_PUBLIC_DEVELOPER_DOCS, }, redirects, + rewrites: async () => [ + { + source: '/:path*.md', + destination: '/md-exports/:path*.md', + }, + ], sassOptions: { silenceDeprecations: ['legacy-js-api'], }, diff --git a/package.json b/package.json index 442c87a9c126c..203edf3cd2e4a 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,10 @@ "dev": "yarn enforce-redirects && concurrently \"yarn sidecar\" \"node ./src/hotReloadWatcher.mjs\" \"next dev\"", "dev:developer-docs": "yarn enforce-redirects && NEXT_PUBLIC_DEVELOPER_DOCS=1 yarn dev", "build:developer-docs": "yarn enforce-redirects && git submodule init && git submodule update && NEXT_PUBLIC_DEVELOPER_DOCS=1 yarn build", - "build": "yarn enforce-redirects && next build", + "build": "yarn enforce-redirects && next build && yarn generate-md-exports", + "generate-md-exports": "node scripts/generate-md-exports.mjs", "vercel:build:developer-docs": "yarn enforce-redirects && git submodule init && git submodule update && NEXT_PUBLIC_DEVELOPER_DOCS=1 yarn build", + "start:dev": "NODE_ENV=development yarn build && yarn start", "start": "next start", "lint": "next lint", "lint:ts": "tsc --skipLibCheck", @@ -61,6 +63,7 @@ "framer-motion": "^10.12.16", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", + "hast-util-select": "^6.0.4", "hast-util-to-jsx-runtime": "^2.3.2", "hastscript": "^8.0.0", "image-size": "^1.2.1", @@ -85,21 +88,26 @@ "react-select": "^5.7.3", "react-textarea-autosize": "^8.5.3", "rehype-autolink-headings": "^7.1.0", + "rehype-parse": "^9.0.1", "rehype-preset-minify": "^7.0.0", "rehype-prism-diff": "^1.1.2", "rehype-prism-plus": "^1.6.3", + "rehype-remark": "^10.0.1", "rehype-stringify": "^10.0.0", - "remark-gfm": "^4.0.0", + "remark-gfm": "^4.0.1", "remark-mdx-images": "^3.0.0", "remark-parse": "^11.0.0", "remark-prism": "^1.3.6", + "remark-stringify": "^11.0.0", "rss": "^1.2.2", "sass": "^1.69.5", "search-insights": "^2.17.2", "server-only": "^0.0.1", "sharp": "^0.33.4", "tailwindcss-scoped-preflight": "^3.0.4", - "textarea-markdown-editor": "^1.0.4" + "textarea-markdown-editor": "^1.0.4", + "unified": "^11.0.5", + "unist-util-remove": "^4.0.0" }, "devDependencies": { "@babel/preset-typescript": "^7.15.0", diff --git a/scripts/generate-md-exports.mjs b/scripts/generate-md-exports.mjs new file mode 100644 index 0000000000000..cd62316c2a904 --- /dev/null +++ b/scripts/generate-md-exports.mjs @@ -0,0 +1,150 @@ +#!/usr/bin/env node + +import {fileURLToPath} from 'url'; + +import {selectAll} from 'hast-util-select'; +import {existsSync} from 'node:fs'; +import {mkdir, opendir, readFile, rm, writeFile} from 'node:fs/promises'; +import {cpus} from 'node:os'; +import * as path from 'node:path'; +import {isMainThread, parentPort, Worker, workerData} from 'node:worker_threads'; +import rehypeParse from 'rehype-parse'; +import rehypeRemark from 'rehype-remark'; +import remarkGfm from 'remark-gfm'; +import remarkStringify from 'remark-stringify'; +import {unified} from 'unified'; +import {remove} from 'unist-util-remove'; + +async function createWork() { + let root = process.cwd(); + while (!existsSync(path.join(root, 'package.json'))) { + const parent = path.dirname(root); + if (parent === root) { + throw new Error('Could not find package.json in parent directories'); + } + root = parent; + } + const INPUT_DIR = path.join(root, '.next', 'server', 'app'); + const OUTPUT_DIR = path.join(root, 'public', 'md-exports'); + + console.log(`🚀 Starting markdown generation from: ${INPUT_DIR}`); + console.log(`📁 Output directory: ${OUTPUT_DIR}`); + + // Clear output directory + await rm(OUTPUT_DIR, {recursive: true, force: true}); + await mkdir(OUTPUT_DIR, {recursive: true}); + + // On a 16-core machine, 8 workers were optimal (and slightly faster than 16) + const numWorkers = Math.max(Math.floor(cpus().length / 2), 2); + const workerTasks = new Array(numWorkers).fill(null).map(() => []); + + console.log(`🔎 Discovering files to convert...`); + + let numFiles = 0; + let workerIdx = 0; + // Need a high buffer size here otherwise Node skips some subdirectories! + // See https://github.com/nodejs/node/issues/48820 + const dir = await opendir(INPUT_DIR, {recursive: true, bufferSize: 1024}); + for await (const dirent of dir) { + if (dirent.name.endsWith('.html') && dirent.isFile()) { + const sourcePath = path.join(dirent.parentPath || dirent.path, dirent.name); + const targetDir = path.join( + OUTPUT_DIR, + path.relative(INPUT_DIR, dirent.parentPath || dirent.path) + ); + await mkdir(targetDir, {recursive: true}); + const targetPath = path.join(targetDir, dirent.name.slice(0, -5) + '.md'); + workerTasks[workerIdx].push({sourcePath, targetPath}); + workerIdx = (workerIdx + 1) % numWorkers; + numFiles++; + } + } + + console.log(`📄 Converting ${numFiles} files with ${numWorkers} workers...`); + + const selfPath = fileURLToPath(import.meta.url); + const workerPromises = new Array(numWorkers - 1).fill(null).map((_, idx) => { + return new Promise((resolve, reject) => { + const worker = new Worker(selfPath, {workerData: workerTasks[idx]}); + let hasErrors = false; + worker.on('message', data => { + if (data.failedTasks.length === 0) { + console.log(`✅ Worker[${idx}]: ${data.success} files successfully.`); + } else { + hasErrors = true; + console.error(`❌ Worker[${idx}]: ${data.failedTasks.length} files failed:`); + console.error(data.failedTasks); + } + }); + worker.on('error', reject); + worker.on('exit', code => { + if (code !== 0) { + reject(new Error(`Worker[${idx}] stopped with exit code ${code}`)); + } else { + hasErrors ? reject(new Error(`Worker[${idx}] had some errors.`)) : resolve(); + } + }); + }); + }); + // The main thread can also process tasks -- That's 65% more bullet per bullet! -Cave Johnson + workerPromises.push(processTaskList(workerTasks[workerTasks.length - 1])); + + await Promise.all(workerPromises); + + console.log(`📄 Generated ${numFiles} markdown files from HTML.`); + console.log('✅ Markdown export generation complete!'); +} + +async function genMDFromHTML(source, target) { + const text = await readFile(source, {encoding: 'utf8'}); + await writeFile( + target, + String( + await unified() + .use(rehypeParse) + // Need the `main div > hgroup` selector for the headers + .use(() => tree => selectAll('main div > hgroup, div#main', tree)) + // If we don't do this wrapping, rehypeRemark just returns an empty string -- yeah WTF? + .use(() => tree => ({ + type: 'element', + tagName: 'div', + properties: {}, + children: tree, + })) + .use(rehypeRemark, { + document: false, + handlers: { + // Remove buttons as they usually get confusing in markdown, especially since we use them as tab headers + button() {}, + }, + }) + // We end up with empty inline code blocks, probably from some tab logic in the HTML, remove them + .use(() => tree => remove(tree, {type: 'inlineCode', value: ''})) + .use(remarkGfm) + .use(remarkStringify) + .process(text) + ) + ); +} + +async function processTaskList(tasks) { + const failedTasks = []; + for (const {sourcePath, targetPath} of tasks) { + try { + await genMDFromHTML(sourcePath, targetPath); + } catch (error) { + failedTasks.push({sourcePath, targetPath, error}); + } + } + return {success: tasks.length - failedTasks.length, failedTasks}; +} + +async function doWork(tasks) { + parentPort.postMessage(await processTaskList(tasks)); +} + +if (isMainThread) { + await createWork(); +} else { + await doWork(workerData); +} diff --git a/src/components/apiExamples/apiExamples.tsx b/src/components/apiExamples/apiExamples.tsx index 28c92259c29c0..ad7226e3e7e86 100644 --- a/src/components/apiExamples/apiExamples.tsx +++ b/src/components/apiExamples/apiExamples.tsx @@ -129,7 +129,11 @@ export function ApiExamples({api}: Props) {
-          
+
Copied
{selectedTabView === 0 && diff --git a/src/components/breadcrumbs/index.tsx b/src/components/breadcrumbs/index.tsx index e86bf2675f471..5fa1e843139d7 100644 --- a/src/components/breadcrumbs/index.tsx +++ b/src/components/breadcrumbs/index.tsx @@ -24,7 +24,7 @@ export function Breadcrumbs({leafNode}: BreadcrumbsProps) { } return ( -
-
+
Copied
diff --git a/src/components/docPage/index.tsx b/src/components/docPage/index.tsx index dde54612f278c..5eabf0cebb79a 100644 --- a/src/components/docPage/index.tsx +++ b/src/components/docPage/index.tsx @@ -1,6 +1,8 @@ import {ReactNode} from 'react'; +import Link from 'next/link'; import {getCurrentGuide, getCurrentPlatform, nodeForPath} from 'sentry-docs/docTree'; +import Markdown from 'sentry-docs/icons/Markdown'; import {serverContext} from 'sentry-docs/serverContext'; import {FrontMatter} from 'sentry-docs/types'; import {PaginationNavNode} from 'sentry-docs/types/paginationNavNode'; @@ -81,7 +83,17 @@ export function DocPage({
- {leafNode && } +
+ {leafNode && }{' '} + + + +

{frontMatter.title}

diff --git a/src/icons/Markdown.tsx b/src/icons/Markdown.tsx new file mode 100644 index 0000000000000..23b950018ce5c --- /dev/null +++ b/src/icons/Markdown.tsx @@ -0,0 +1,15 @@ +function Markdown({width = 16, height = 16, ...props}: React.SVGAttributes) { + return ( + + + + ); +} +export default Markdown; diff --git a/src/mdx.ts b/src/mdx.ts index 3eb125b0f344b..d7dcc5ecda78d 100644 --- a/src/mdx.ts +++ b/src/mdx.ts @@ -429,9 +429,9 @@ export async function getFileBySlug(slug: string) { ], }, ], - [rehypePrismPlus, {ignoreMissing: true}], + [rehypePrismPlus, {ignoreMissing: true}] as any, rehypeOnboardingLines, - [rehypePrismDiff, {remove: true}], + [rehypePrismDiff, {remove: true}] as any, rehypePresetMinify, ]; return options; diff --git a/yarn.lock b/yarn.lock index bfa94b4cde487..cc68e32c1b4f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6893,6 +6893,18 @@ hast-util-embedded@^3.0.0: "@types/hast" "^3.0.0" hast-util-is-element "^3.0.0" +hast-util-from-html@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz#485c74785358beb80c4ba6346299311ac4c49c82" + integrity sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.1.0" + hast-util-from-parse5 "^8.0.0" + parse5 "^7.0.0" + vfile "^6.0.0" + vfile-message "^4.0.0" + hast-util-from-parse5@^7.0.0: version "7.1.2" resolved "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz" @@ -6906,6 +6918,20 @@ hast-util-from-parse5@^7.0.0: vfile-location "^4.0.0" web-namespaces "^2.0.0" +hast-util-from-parse5@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz#830a35022fff28c3fea3697a98c2f4cc6b835a2e" + integrity sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + hastscript "^9.0.0" + property-information "^7.0.0" + vfile "^6.0.0" + vfile-location "^5.0.0" + web-namespaces "^2.0.0" + hast-util-from-string@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/hast-util-from-string/-/hast-util-from-string-2.0.0.tgz" @@ -6934,6 +6960,13 @@ hast-util-heading-rank@^3.0.0: dependencies: "@types/hast" "^3.0.0" +hast-util-is-body-ok-link@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-3.0.1.tgz#ef63cb2f14f04ecf775139cd92bda5026380d8b4" + integrity sha512-0qpnzOBLztXHbHQenVB8uNuxTnm/QBFUOmdOSsEn7GnBtyY07+ENTWVFBAnXd/zEgd9/SUG3lRY7hSIBWRgGpQ== + dependencies: + "@types/hast" "^3.0.0" + hast-util-is-conditional-comment@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/hast-util-is-conditional-comment/-/hast-util-is-conditional-comment-3.0.1.tgz" @@ -7002,6 +7035,17 @@ hast-util-parse-selector@^4.0.0: dependencies: "@types/hast" "^3.0.0" +hast-util-phrasing@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/hast-util-phrasing/-/hast-util-phrasing-3.0.1.tgz#fa284c0cd4a82a0dd6020de8300a7b1ebffa1690" + integrity sha512-6h60VfI3uBQUxHqTyMymMZnEbNl1XmEGtOxxKYL7stY2o601COo62AWAYBQR9lZbYXYSBoxag8UpPRXK+9fqSQ== + dependencies: + "@types/hast" "^3.0.0" + hast-util-embedded "^3.0.0" + hast-util-has-property "^3.0.0" + hast-util-is-body-ok-link "^3.0.0" + hast-util-is-element "^3.0.0" + hast-util-select@^6.0.0: version "6.0.3" resolved "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.3.tgz" @@ -7023,6 +7067,27 @@ hast-util-select@^6.0.0: unist-util-visit "^5.0.0" zwitch "^2.0.0" +hast-util-select@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/hast-util-select/-/hast-util-select-6.0.4.tgz#1d8f69657a57441d0ce0ade35887874d3e65a303" + integrity sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + bcp-47-match "^2.0.0" + comma-separated-tokens "^2.0.0" + css-selector-parser "^3.0.0" + devlop "^1.0.0" + direction "^2.0.0" + hast-util-has-property "^3.0.0" + hast-util-to-string "^3.0.0" + hast-util-whitespace "^3.0.0" + nth-check "^2.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + unist-util-visit "^5.0.0" + zwitch "^2.0.0" + hast-util-to-estree@^2.0.0: version "2.3.3" resolved "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-2.3.3.tgz" @@ -7104,6 +7169,26 @@ hast-util-to-jsx-runtime@^2.0.0, hast-util-to-jsx-runtime@^2.3.2: unist-util-position "^5.0.0" vfile-message "^4.0.0" +hast-util-to-mdast@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/hast-util-to-mdast/-/hast-util-to-mdast-10.1.2.tgz#bc76f7f5f72f2cde4d6a66ad4cd0aba82bb79909" + integrity sha512-FiCRI7NmOvM4y+f5w32jPRzcxDIz+PUqDwEqn1A+1q2cdp3B8Gx7aVrXORdOKjMNDQsD1ogOr896+0jJHW1EFQ== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + "@ungap/structured-clone" "^1.0.0" + hast-util-phrasing "^3.0.0" + hast-util-to-html "^9.0.0" + hast-util-to-text "^4.0.0" + hast-util-whitespace "^3.0.0" + mdast-util-phrasing "^4.0.0" + mdast-util-to-hast "^13.0.0" + mdast-util-to-string "^4.0.0" + rehype-minify-whitespace "^6.0.0" + trim-trailing-lines "^2.0.0" + unist-util-position "^5.0.0" + unist-util-visit "^5.0.0" + hast-util-to-string@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-2.0.0.tgz" @@ -7118,6 +7203,16 @@ hast-util-to-string@^3.0.0: dependencies: "@types/hast" "^3.0.0" +hast-util-to-text@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz#57b676931e71bf9cb852453678495b3080bfae3e" + integrity sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A== + dependencies: + "@types/hast" "^3.0.0" + "@types/unist" "^3.0.0" + hast-util-is-element "^3.0.0" + unist-util-find-after "^5.0.0" + hast-util-whitespace@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz" @@ -7152,6 +7247,17 @@ hastscript@^8.0.0: property-information "^6.0.0" space-separated-tokens "^2.0.0" +hastscript@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-9.0.1.tgz#dbc84bef6051d40084342c229c451cd9dc567dff" + integrity sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w== + dependencies: + "@types/hast" "^3.0.0" + comma-separated-tokens "^2.0.0" + hast-util-parse-selector "^4.0.0" + property-information "^7.0.0" + space-separated-tokens "^2.0.0" + hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" @@ -10365,6 +10471,11 @@ property-information@^6.0.0: resolved "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz" integrity sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig== +property-information@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-7.1.0.tgz#b622e8646e02b580205415586b40804d3e8bfd5d" + integrity sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ== + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" @@ -10791,6 +10902,15 @@ rehype-parse@^8.0.2: parse5 "^6.0.0" unified "^10.0.0" +rehype-parse@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-9.0.1.tgz#9993bda129acc64c417a9d3654a7be38b2a94c20" + integrity sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag== + dependencies: + "@types/hast" "^3.0.0" + hast-util-from-html "^2.0.0" + unified "^11.0.0" + rehype-preset-minify@^7.0.0: version "7.0.1" resolved "https://registry.npmjs.org/rehype-preset-minify/-/rehype-preset-minify-7.0.1.tgz" @@ -10851,6 +10971,17 @@ rehype-recma@^1.0.0: "@types/hast" "^3.0.0" hast-util-to-estree "^3.0.0" +rehype-remark@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/rehype-remark/-/rehype-remark-10.0.1.tgz#f669fa68cfb8b5baaf4fa95476a923516111a43b" + integrity sha512-EmDndlb5NVwXGfUa4c9GPK+lXeItTilLhE6ADSaQuHr4JUlKw9MidzGzx4HpqZrNCt6vnHmEifXQiiA+CEnjYQ== + dependencies: + "@types/hast" "^3.0.0" + "@types/mdast" "^4.0.0" + hast-util-to-mdast "^10.0.0" + unified "^11.0.0" + vfile "^6.0.0" + rehype-remove-comments@^6.0.0: version "6.1.1" resolved "https://registry.npmjs.org/rehype-remove-comments/-/rehype-remove-comments-6.1.1.tgz" @@ -10952,10 +11083,10 @@ remark-frontmatter@^5.0.0: micromark-extension-frontmatter "^2.0.0" unified "^11.0.0" -remark-gfm@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz" - integrity sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA== +remark-gfm@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-4.0.1.tgz#33227b2a74397670d357bf05c098eaf8513f0d6b" + integrity sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg== dependencies: "@types/mdast" "^4.0.0" mdast-util-gfm "^3.0.0" @@ -11975,6 +12106,11 @@ trim-lines@^3.0.0: resolved "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz" integrity sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg== +trim-trailing-lines@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-2.1.0.tgz#9aac7e89b09cb35badf663de7133c6de164f86df" + integrity sha512-5UR5Biq4VlVOtzqkm2AZlgvSlDJtME46uV0br0gENbwN4l5+mMKT4b9gJKqWtuL2zAIqajGJGuvbCbcAJUZqBg== + trough@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz" @@ -12173,7 +12309,7 @@ unified@^10.0.0: trough "^2.0.0" vfile "^5.0.0" -unified@^11.0.0: +unified@^11.0.0, unified@^11.0.5: version "11.0.5" resolved "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz" integrity sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA== @@ -12195,6 +12331,14 @@ unist-util-filter@^4.0.0: unist-util-is "^5.0.0" unist-util-visit-parents "^5.0.0" +unist-util-find-after@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz#3fccc1b086b56f34c8b798e1ff90b5c54468e896" + integrity sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-generated@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz" @@ -12258,6 +12402,15 @@ unist-util-remove-position@^4.0.0: "@types/unist" "^2.0.0" unist-util-visit "^4.0.0" +unist-util-remove@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-4.0.0.tgz#94b7d6bbd24e42d2f841e947ed087be5c82b222e" + integrity sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg== + dependencies: + "@types/unist" "^3.0.0" + unist-util-is "^6.0.0" + unist-util-visit-parents "^6.0.0" + unist-util-stringify-position@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz" @@ -12441,6 +12594,14 @@ vfile-location@^4.0.0: "@types/unist" "^2.0.0" vfile "^5.0.0" +vfile-location@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-5.0.3.tgz#cb9eacd20f2b6426d19451e0eafa3d0a846225c3" + integrity sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg== + dependencies: + "@types/unist" "^3.0.0" + vfile "^6.0.0" + vfile-matter@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/vfile-matter/-/vfile-matter-3.0.1.tgz"