From b26cdb3e46901ec433701a21123391a3b845c6e2 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Tue, 3 Jan 2023 05:59:24 +0000 Subject: [PATCH 1/5] build(docs): support YAML frontmatter in markdown Vitepress uses YAML frontmatter to configure Vitepress specific settings, see https://vitepress.vuejs.org/config/frontmatter-configs We just need to use `remark-frontmatter` to add support for it. GitHub also renders the YAML front-matter nicely in a table automatically, but maybe we should instead strip it, if it's only used by Vitepress? --- packages/mermaid/package.json | 1 + packages/mermaid/src/docs.mts | 7 ++++-- pnpm-lock.yaml | 45 +++++++++++++++++++++++++++++++---- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/mermaid/package.json b/packages/mermaid/package.json index c5699ae281..f7eff67318 100644 --- a/packages/mermaid/package.json +++ b/packages/mermaid/package.json @@ -90,6 +90,7 @@ "path-browserify": "^1.0.1", "prettier": "^2.7.1", "remark": "^14.0.2", + "remark-frontmatter": "^4.0.1", "remark-gfm": "^3.0.1", "rimraf": "^3.0.2", "start-server-and-test": "^1.14.0", diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 99da3f3813..7a32e34ee0 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -38,14 +38,17 @@ import type { Code, Root } from 'mdast'; import { posix, dirname, relative, join } from 'path'; import prettier from 'prettier'; import { remark as remarkBuilder } from 'remark'; +import remarkFrontmatter from 'remark-frontmatter'; import remarkGfm from 'remark-gfm'; import chokidar from 'chokidar'; import mm from 'micromatch'; // @ts-ignore No typescript declaration file import flatmap from 'unist-util-flatmap'; -// support tables and other GitHub Flavored Markdown syntax in markdown -const remark = remarkBuilder().use(remarkGfm); +const remark = remarkBuilder() + // support tables and other GitHub Flavored Markdown syntax in markdown + .use(remarkGfm) + .use(remarkFrontmatter, ['yaml']); // support YAML front-matter in Markdown const MERMAID_MAJOR_VERSION = ( JSON.parse(readFileSync('../mermaid/package.json', 'utf8')).version as string diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dfc7885973..7ab8e73405 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -275,6 +275,9 @@ importers: remark: specifier: ^14.0.2 version: 14.0.2 + remark-frontmatter: + specifier: ^4.0.1 + version: 4.0.1 remark-gfm: specifier: ^3.0.1 version: 3.0.1 @@ -3970,7 +3973,7 @@ packages: /axios/0.21.4_debug@4.3.2: resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.15.2_debug@4.3.2 + follow-redirects: 1.15.2 transitivePeerDependencies: - debug dev: true @@ -6663,6 +6666,12 @@ packages: reusify: 1.0.4 dev: true + /fault/2.0.1: + resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} + dependencies: + format: 0.2.2 + dev: true + /faye-websocket/0.11.4: resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} engines: {node: '>=0.8.0'} @@ -6762,7 +6771,7 @@ packages: resolution: {integrity: sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA==} dev: true - /follow-redirects/1.15.2_debug@4.3.2: + /follow-redirects/1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} peerDependencies: @@ -6770,8 +6779,6 @@ packages: peerDependenciesMeta: debug: optional: true - dependencies: - debug: 4.3.2 dev: true /foreground-child/2.0.0: @@ -6813,6 +6820,11 @@ packages: mime-types: 2.1.35 dev: true + /format/0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + dev: true + /forwarded/0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -7306,7 +7318,7 @@ packages: engines: {node: '>=8.0.0'} dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.2_debug@4.3.2 + follow-redirects: 1.15.2 requires-port: 1.0.0 transitivePeerDependencies: - debug @@ -8747,6 +8759,12 @@ packages: - supports-color dev: true + /mdast-util-frontmatter/1.0.0: + resolution: {integrity: sha512-7itKvp0arEVNpCktOET/eLFAYaZ+0cNjVtFtIPxgQ5tV+3i+D4SDDTjTzPWl44LT59PC+xdx+glNTawBdF98Mw==} + dependencies: + micromark-extension-frontmatter: 1.0.0 + dev: true + /mdast-util-gfm-autolink-literal/1.0.2: resolution: {integrity: sha512-FzopkOd4xTTBeGXhXSBU0OCDDh5lUj2rd+HQqG92Ld+jL4lpUfgX2AT2OHAVP9aEeDKp7G92fuooSZcYJA3cRg==} dependencies: @@ -8917,6 +8935,14 @@ packages: uvu: 0.5.6 dev: true + /micromark-extension-frontmatter/1.0.0: + resolution: {integrity: sha512-EXjmRnupoX6yYuUJSQhrQ9ggK0iQtQlpi6xeJzVD5xscyAI+giqco5fdymayZhJMbIFecjnE2yz85S9NzIgQpg==} + dependencies: + fault: 2.0.1 + micromark-util-character: 1.1.0 + micromark-util-symbol: 1.0.1 + dev: true + /micromark-extension-gfm-autolink-literal/1.0.3: resolution: {integrity: sha512-i3dmvU0htawfWED8aHMMAzAVp/F0Z+0bPh3YrbTPPL1v4YAlCZpy5rBO5p0LPYiZo0zFVkoYh7vDU7yQSiCMjg==} dependencies: @@ -10148,6 +10174,15 @@ packages: jsesc: 0.5.0 dev: true + /remark-frontmatter/4.0.1: + resolution: {integrity: sha512-38fJrB0KnmD3E33a5jZC/5+gGAC2WKNiPw1/fdXJvijBlhA7RCsvJklrYJakS0HedninvaCYW8lQGf9C918GfA==} + dependencies: + '@types/mdast': 3.0.10 + mdast-util-frontmatter: 1.0.0 + micromark-extension-frontmatter: 1.0.0 + unified: 10.1.2 + dev: true + /remark-gfm/3.0.1: resolution: {integrity: sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==} dependencies: From 8f4caa4537417bea52a551d6ac333825e2639519 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Sat, 14 Jan 2023 01:57:59 +0000 Subject: [PATCH 2/5] refactor(docs): use remark-compatible plugin Change the `transformBlocks` function, which transforms a markdown str, and instead making it into a `transformMarkdownAst` function, which transforms a Markdown AST. This means we can use the remark/unifiedjs plugin infrastructure, see https://unifiedjs.com/learn/guide/create-a-plugin/ --- packages/mermaid/src/docs.mts | 83 +++++++++++++++---------------- packages/mermaid/src/docs.spec.ts | 50 +++++++------------ 2 files changed, 59 insertions(+), 74 deletions(-) diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 7a32e34ee0..4fe18001b9 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -37,7 +37,7 @@ import { JSDOM } from 'jsdom'; import type { Code, Root } from 'mdast'; import { posix, dirname, relative, join } from 'path'; import prettier from 'prettier'; -import { remark as remarkBuilder } from 'remark'; +import { remark } from 'remark'; import remarkFrontmatter from 'remark-frontmatter'; import remarkGfm from 'remark-gfm'; import chokidar from 'chokidar'; @@ -45,11 +45,6 @@ import mm from 'micromatch'; // @ts-ignore No typescript declaration file import flatmap from 'unist-util-flatmap'; -const remark = remarkBuilder() - // support tables and other GitHub Flavored Markdown syntax in markdown - .use(remarkGfm) - .use(remarkFrontmatter, ['yaml']); // support YAML front-matter in Markdown - const MERMAID_MAJOR_VERSION = ( JSON.parse(readFileSync('../mermaid/package.json', 'utf8')).version as string ).split('.')[0]; @@ -205,47 +200,45 @@ const transformIncludeStatements = (file: string, text: string): string => { }; /** - * Transform code blocks in a Markdown file. - * Use remark.parse() to turn the given content (a String) into an AST. + * Remark plugin that transforms code blocks in a Markdown file. + * * For any AST node that is a code block: transform it as needed: * - blocks marked as MERMAID_DIAGRAM_ONLY will be set to a 'mermaid' code block so it will be rendered as (only) a diagram * - blocks marked as MERMAID_EXAMPLE_KEYWORDS will be copied and the original node will be a code only block and the copy with be rendered as the diagram * - blocks marked as BLOCK_QUOTE_KEYWORDS will be transformed into block quotes * - * Convert the AST back to a string and return it. - * - * @param content - the contents of a Markdown file - * @returns the contents with transformed code blocks + * @returns plugin function for Remark */ -export const transformBlocks = (content: string): string => { - const ast: Root = remark.parse(content); - const astWithTransformedBlocks = flatmap(ast, (node: Code) => { - if (node.type !== 'code' || !node.lang) { - return [node]; // no transformation if this is not a code block - } - - if (node.lang === MERMAID_DIAGRAM_ONLY) { - // Set the lang to 'mermaid' so it will be rendered as a diagram. - node.lang = MERMAID_KEYWORD; - return [node]; - } else if (MERMAID_EXAMPLE_KEYWORDS.includes(node.lang)) { - // Return 2 nodes: - // 1. the original node with the language now set to 'mermaid-example' (will be rendered as code), and - // 2. a copy of the original node with the language set to 'mermaid' (will be rendered as a diagram) - node.lang = MERMAID_CODE_ONLY_KEYWORD; - return [node, Object.assign({}, node, { lang: MERMAID_KEYWORD })]; - } - - // Transform these blocks into block quotes. - if (BLOCK_QUOTE_KEYWORDS.includes(node.lang)) { - return [remark.parse(transformToBlockQuote(node.value, node.lang, node.meta))]; - } - - return [node]; // default is to do nothing to the node - }); - - return remark.stringify(astWithTransformedBlocks); -}; +export function transformMarkdownAst() { + return (tree: Root, _file?: any): Root => { + const astWithTransformedBlocks = flatmap(tree, (node: Code) => { + if (node.type !== 'code' || !node.lang) { + return [node]; // no transformation if this is not a code block + } + + if (node.lang === MERMAID_DIAGRAM_ONLY) { + // Set the lang to 'mermaid' so it will be rendered as a diagram. + node.lang = MERMAID_KEYWORD; + return [node]; + } else if (MERMAID_EXAMPLE_KEYWORDS.includes(node.lang)) { + // Return 2 nodes: + // 1. the original node with the language now set to 'mermaid-example' (will be rendered as code), and + // 2. a copy of the original node with the language set to 'mermaid' (will be rendered as a diagram) + node.lang = MERMAID_CODE_ONLY_KEYWORD; + return [node, Object.assign({}, node, { lang: MERMAID_KEYWORD })]; + } + + // Transform these blocks into block quotes. + if (BLOCK_QUOTE_KEYWORDS.includes(node.lang)) { + return [remark.parse(transformToBlockQuote(node.value, node.lang, node.meta))]; + } + + return [node]; // default is to do nothing to the node + }); + + return astWithTransformedBlocks; + }; +} /** * Transform a markdown file and write the transformed file to the directory for published @@ -263,7 +256,13 @@ export const transformBlocks = (content: string): string => { */ const transformMarkdown = (file: string) => { const doc = injectPlaceholders(transformIncludeStatements(file, readSyncedUTF8file(file))); - let transformed = transformBlocks(doc); + + let transformed = remark() + .use(remarkGfm) + .use(remarkFrontmatter, ['yaml']) // support YAML front-matter in Markdown + .use(transformMarkdownAst) // mermaid project specific plugin + .processSync(doc).toString(); + if (!noHeader) { // Add the header to the start of the file transformed = `${generateHeader(file)}\n${transformed}`; diff --git a/packages/mermaid/src/docs.spec.ts b/packages/mermaid/src/docs.spec.ts index ea5f54d692..5b47146d58 100644 --- a/packages/mermaid/src/docs.spec.ts +++ b/packages/mermaid/src/docs.spec.ts @@ -1,40 +1,20 @@ -import { transformBlocks, transformToBlockQuote } from './docs.mjs'; +import { transformMarkdownAst, transformToBlockQuote } from './docs.mjs'; + import { remark as remarkBuilder } from 'remark'; // import it this way so we can mock it import { vi, afterEach, describe, it, expect } from 'vitest'; -const remark = remarkBuilder(); - -vi.mock('remark', async (importOriginal) => { - const { remark: originalRemarkBuilder } = (await importOriginal()) as { - remark: typeof remarkBuilder; - }; - - // make sure that both `docs.mts` and this test file are using the same remark - // object so that we can mock it - const sharedRemark = originalRemarkBuilder(); - return { - remark: () => sharedRemark, - }; -}); - afterEach(() => { vi.restoreAllMocks(); }); describe('docs.mts', () => { - describe('transformBlocks', () => { - it('uses remark.parse to create the AST for the file ', () => { - const remarkParseSpy = vi - .spyOn(remark, 'parse') - .mockReturnValue({ type: 'root', children: [] }); - const contents = 'Markdown file contents'; - transformBlocks(contents); - expect(remarkParseSpy).toHaveBeenCalledWith(contents); - }); + describe('transformMarkdownAst', () => { describe('checks each AST node', () => { it('does no transformation if there are no code blocks', async () => { const contents = 'Markdown file contents\n'; - const result = transformBlocks(contents); + const result = ( + await remarkBuilder().use(transformMarkdownAst).process(contents) + ).toString(); expect(result).toEqual(contents); }); @@ -46,8 +26,10 @@ describe('docs.mts', () => { const lang_keyword = 'mermaid-nocode'; const contents = beforeCodeLine + '```' + lang_keyword + '\n' + diagram_text + '\n```\n'; - it('changes the language to "mermaid"', () => { - const result = transformBlocks(contents); + it('changes the language to "mermaid"', async () => { + const result = ( + await remarkBuilder().use(transformMarkdownAst).process(contents) + ).toString(); expect(result).toEqual( beforeCodeLine + '\n' + '```' + 'mermaid' + '\n' + diagram_text + '\n```\n' ); @@ -61,8 +43,10 @@ describe('docs.mts', () => { const contents = beforeCodeLine + '```' + lang_keyword + '\n' + diagram_text + '\n```\n'; - it('changes the language to "mermaid-example" and adds a copy of the code block with language = "mermaid"', () => { - const result = transformBlocks(contents); + it('changes the language to "mermaid-example" and adds a copy of the code block with language = "mermaid"', async () => { + const result = ( + await remarkBuilder().use(transformMarkdownAst).process(contents) + ).toString(); expect(result).toEqual( beforeCodeLine + '\n' + @@ -77,12 +61,14 @@ describe('docs.mts', () => { }); }); - it('calls transformToBlockQuote with the node information', () => { + it('calls transformToBlockQuote with the node information', async () => { const lang_keyword = 'note'; const contents = beforeCodeLine + '```' + lang_keyword + '\n' + 'This is the text\n' + '```\n'; - const result = transformBlocks(contents); + const result = ( + await remarkBuilder().use(transformMarkdownAst).process(contents) + ).toString(); expect(result).toEqual(beforeCodeLine + '\n> **Note**\n' + '> This is the text\n'); }); }); From 2f1a521db65d7fe77bcf050c24469db43a573b3d Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Thu, 19 Jan 2023 00:06:58 +0000 Subject: [PATCH 3/5] build(docs): add auto-generated header after YAML Add the auto-generated header after any YAML front-matter blocks. YAML front-matter is normally only valid in Markdown when it's at the beginning of the Markdown file. GitHub/Vitepress may otherwise render it incorrectly. --- packages/mermaid/src/docs.mts | 40 ++++++++++++++++++++++++------- packages/mermaid/src/docs.spec.ts | 14 +++++++---- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 4fe18001b9..07f393df14 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -199,17 +199,32 @@ const transformIncludeStatements = (file: string, text: string): string => { }); }; +/** Options for {@link transformMarkdownAst} */ +interface TransformMarkdownAstOptions { + /** + * Used to indicate the original/source file. + */ + originalFilename: string; + /** If `true`, add a warning that the file is autogenerated */ + addAutogeneratedWarning?: boolean; +} + /** - * Remark plugin that transforms code blocks in a Markdown file. + * Remark plugin that transforms mermaid repo markdown to Vitepress/GFM markdown. * * For any AST node that is a code block: transform it as needed: * - blocks marked as MERMAID_DIAGRAM_ONLY will be set to a 'mermaid' code block so it will be rendered as (only) a diagram * - blocks marked as MERMAID_EXAMPLE_KEYWORDS will be copied and the original node will be a code only block and the copy with be rendered as the diagram * - blocks marked as BLOCK_QUOTE_KEYWORDS will be transformed into block quotes * + * If `addAutogeneratedWarning` is `true`, generates a header stating that this file is autogenerated. + * * @returns plugin function for Remark */ -export function transformMarkdownAst() { +export function transformMarkdownAst({ + originalFilename, + addAutogeneratedWarning, +}: TransformMarkdownAstOptions) { return (tree: Root, _file?: any): Root => { const astWithTransformedBlocks = flatmap(tree, (node: Code) => { if (node.type !== 'code' || !node.lang) { @@ -236,6 +251,17 @@ export function transformMarkdownAst() { return [node]; // default is to do nothing to the node }); + if (addAutogeneratedWarning) { + // Add the header to the start of the file + const headerNode = remark.parse(generateHeader(originalFilename)).children[0]; + if (astWithTransformedBlocks.children[0].type === 'yaml') { + // insert header after the YAML frontmatter if it exists + astWithTransformedBlocks.children.splice(1, 0, headerNode); + } else { + astWithTransformedBlocks.children.unshift(headerNode); + } + } + return astWithTransformedBlocks; }; } @@ -260,13 +286,9 @@ const transformMarkdown = (file: string) => { let transformed = remark() .use(remarkGfm) .use(remarkFrontmatter, ['yaml']) // support YAML front-matter in Markdown - .use(transformMarkdownAst) // mermaid project specific plugin - .processSync(doc).toString(); - - if (!noHeader) { - // Add the header to the start of the file - transformed = `${generateHeader(file)}\n${transformed}`; - } + .use(transformMarkdownAst, { originalFilename: file, addAutogeneratedWarning: !noHeader }) // mermaid project specific plugin + .processSync(doc) + .toString(); if (vitepress && file === 'src/docs/index.md') { // Skip transforming index if vitepress is enabled diff --git a/packages/mermaid/src/docs.spec.ts b/packages/mermaid/src/docs.spec.ts index 5b47146d58..1ce708e935 100644 --- a/packages/mermaid/src/docs.spec.ts +++ b/packages/mermaid/src/docs.spec.ts @@ -7,13 +7,15 @@ afterEach(() => { vi.restoreAllMocks(); }); +const originalFilename = 'example-input-filename.md'; + describe('docs.mts', () => { describe('transformMarkdownAst', () => { describe('checks each AST node', () => { it('does no transformation if there are no code blocks', async () => { const contents = 'Markdown file contents\n'; const result = ( - await remarkBuilder().use(transformMarkdownAst).process(contents) + await remarkBuilder().use(transformMarkdownAst, { originalFilename }).process(contents) ).toString(); expect(result).toEqual(contents); }); @@ -28,7 +30,9 @@ describe('docs.mts', () => { it('changes the language to "mermaid"', async () => { const result = ( - await remarkBuilder().use(transformMarkdownAst).process(contents) + await remarkBuilder() + .use(transformMarkdownAst, { originalFilename }) + .process(contents) ).toString(); expect(result).toEqual( beforeCodeLine + '\n' + '```' + 'mermaid' + '\n' + diagram_text + '\n```\n' @@ -45,7 +49,9 @@ describe('docs.mts', () => { it('changes the language to "mermaid-example" and adds a copy of the code block with language = "mermaid"', async () => { const result = ( - await remarkBuilder().use(transformMarkdownAst).process(contents) + await remarkBuilder() + .use(transformMarkdownAst, { originalFilename }) + .process(contents) ).toString(); expect(result).toEqual( beforeCodeLine + @@ -67,7 +73,7 @@ describe('docs.mts', () => { beforeCodeLine + '```' + lang_keyword + '\n' + 'This is the text\n' + '```\n'; const result = ( - await remarkBuilder().use(transformMarkdownAst).process(contents) + await remarkBuilder().use(transformMarkdownAst, { originalFilename }).process(contents) ).toString(); expect(result).toEqual(beforeCodeLine + '\n> **Note**\n' + '> This is the text\n'); }); From 76c3716b2d070762208968fab2313025612197d0 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Tue, 3 Jan 2023 06:03:27 +0000 Subject: [PATCH 4/5] docs: add vitepress metadata to flowchart docs Changes the title in Vitepress, as well as using `outline: "deep"` for a better outline/table-of-contents for the page. See https://vitepress.vuejs.org/config/theme-configs#outline for docs on what `outline: "deep"` does. --- docs/syntax/flowchart.md | 5 +++++ packages/mermaid/src/docs/syntax/flowchart.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md index 0ef94d24b4..b31b27c477 100644 --- a/docs/syntax/flowchart.md +++ b/docs/syntax/flowchart.md @@ -1,3 +1,8 @@ +--- +title: Flowcharts Syntax +outline: 'deep' # shows all h3 headings in outline in Vitepress +--- + > **Warning** > > ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. diff --git a/packages/mermaid/src/docs/syntax/flowchart.md b/packages/mermaid/src/docs/syntax/flowchart.md index 9a0e7bc247..4ca3c5466b 100644 --- a/packages/mermaid/src/docs/syntax/flowchart.md +++ b/packages/mermaid/src/docs/syntax/flowchart.md @@ -1,3 +1,8 @@ +--- +title: Flowcharts Syntax +outline: 'deep' # shows all h3 headings in outline in Vitepress +--- + # Flowcharts - Basic Syntax All Flowcharts are composed of **nodes**, the geometric shapes and **edges**, the arrows or lines. The mermaid code defines the way that these **nodes** and **edges** are made and interact. From 816f2f512e4ff85d9ce9be8b25f0686815640c23 Mon Sep 17 00:00:00 2001 From: Alois Klink Date: Sun, 22 Jan 2023 19:12:13 +0000 Subject: [PATCH 5/5] build(docs): hide YAML when building for GitHub YAML front-matter is currently only used for Vitepress. Because of that, to avoid confusion, we can remove this YAML front-matter when converting the Markdown in packages/mermaid/src/docs to go into the `docs/` folder for GitHub browsing. --- docs/syntax/flowchart.md | 5 ----- packages/mermaid/src/docs.mts | 23 +++++++++++++++++++++-- packages/mermaid/src/docs.spec.ts | 26 +++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/docs/syntax/flowchart.md b/docs/syntax/flowchart.md index b31b27c477..0ef94d24b4 100644 --- a/docs/syntax/flowchart.md +++ b/docs/syntax/flowchart.md @@ -1,8 +1,3 @@ ---- -title: Flowcharts Syntax -outline: 'deep' # shows all h3 headings in outline in Vitepress ---- - > **Warning** > > ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. diff --git a/packages/mermaid/src/docs.mts b/packages/mermaid/src/docs.mts index 07f393df14..e221984b33 100644 --- a/packages/mermaid/src/docs.mts +++ b/packages/mermaid/src/docs.mts @@ -207,6 +207,11 @@ interface TransformMarkdownAstOptions { originalFilename: string; /** If `true`, add a warning that the file is autogenerated */ addAutogeneratedWarning?: boolean; + /** + * If `true`, remove the YAML metadata from the Markdown input. + * Generally, YAML metadata is only used for Vitepress. + */ + removeYAML?: boolean; } /** @@ -224,6 +229,7 @@ interface TransformMarkdownAstOptions { export function transformMarkdownAst({ originalFilename, addAutogeneratedWarning, + removeYAML, }: TransformMarkdownAstOptions) { return (tree: Root, _file?: any): Root => { const astWithTransformedBlocks = flatmap(tree, (node: Code) => { @@ -249,7 +255,7 @@ export function transformMarkdownAst({ } return [node]; // default is to do nothing to the node - }); + }) as Root; if (addAutogeneratedWarning) { // Add the header to the start of the file @@ -262,6 +268,14 @@ export function transformMarkdownAst({ } } + if (removeYAML) { + const firstNode = astWithTransformedBlocks.children[0]; + if (firstNode.type == 'yaml') { + // YAML is currently only used for Vitepress metadata, so we should remove it for GFM output + astWithTransformedBlocks.children.shift(); + } + } + return astWithTransformedBlocks; }; } @@ -286,7 +300,12 @@ const transformMarkdown = (file: string) => { let transformed = remark() .use(remarkGfm) .use(remarkFrontmatter, ['yaml']) // support YAML front-matter in Markdown - .use(transformMarkdownAst, { originalFilename: file, addAutogeneratedWarning: !noHeader }) // mermaid project specific plugin + .use(transformMarkdownAst, { + // mermaid project specific plugin + originalFilename: file, + addAutogeneratedWarning: !noHeader, + removeYAML: !noHeader, + }) .processSync(doc) .toString(); diff --git a/packages/mermaid/src/docs.spec.ts b/packages/mermaid/src/docs.spec.ts index 1ce708e935..50feaee6ad 100644 --- a/packages/mermaid/src/docs.spec.ts +++ b/packages/mermaid/src/docs.spec.ts @@ -1,6 +1,7 @@ import { transformMarkdownAst, transformToBlockQuote } from './docs.mjs'; -import { remark as remarkBuilder } from 'remark'; // import it this way so we can mock it +import { remark } from 'remark'; // import it this way so we can mock it +import remarkFrontmatter from 'remark-frontmatter'; import { vi, afterEach, describe, it, expect } from 'vitest'; afterEach(() => { @@ -8,6 +9,7 @@ afterEach(() => { }); const originalFilename = 'example-input-filename.md'; +const remarkBuilder = remark().use(remarkFrontmatter, ['yaml']); // support YAML front-matter in Markdown describe('docs.mts', () => { describe('transformMarkdownAst', () => { @@ -79,6 +81,28 @@ describe('docs.mts', () => { }); }); }); + + it('should remove YAML if `removeYAML` is true', async () => { + const contents = `--- +title: Flowcharts Syntax +--- + +This Markdown should be kept. +`; + const withYaml = ( + await remarkBuilder().use(transformMarkdownAst, { originalFilename }).process(contents) + ).toString(); + // no change + expect(withYaml).toEqual(contents); + + const withoutYaml = ( + await remarkBuilder() + .use(transformMarkdownAst, { originalFilename, removeYAML: true }) + .process(contents) + ).toString(); + // no change + expect(withoutYaml).toEqual('This Markdown should be kept.\n'); + }); }); describe('transformToBlockQuote', () => {