Skip to content

Commit ecd9e46

Browse files
authoredApr 22, 2024
Merge pull request #21 from Mermaid-Chart/fix/keep-comments-in-yaml
fix(cli): keep comments in YAML frontmatter
2 parents ce94af6 + c0af0f6 commit ecd9e46

File tree

5 files changed

+49
-54
lines changed

5 files changed

+49
-54
lines changed
 

‎packages/cli/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@
5959
"@inquirer/select": "^1.3.1",
6060
"@mermaidchart/sdk": "workspace:^",
6161
"commander": "^11.1.0",
62-
"js-yaml": "^4.1.0",
6362
"remark": "^15.0.1",
6463
"remark-frontmatter": "^5.0.0",
6564
"remark-gfm": "^4.0.0",
6665
"to-vfile": "^8.0.0",
67-
"unist-util-visit": "^5.0.0"
66+
"unist-util-visit": "^5.0.0",
67+
"yaml": "^2.3.4"
6868
}
6969
}

‎packages/cli/src/commander.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ describe('pull', () => {
435435
const mockedDiagram = {
436436
...mockedEmptyDiagram,
437437
code: `---
438+
# comments in YAML shouldn't be removed
438439
title: My cool flowchart
439440
---
440441
flowchart TD
@@ -453,6 +454,7 @@ title: My cool flowchart
453454
expect(diagramContents).toContain(
454455
`id: https://test.mermaidchart.invalid/d/${mockedDiagram.documentID}`,
455456
);
457+
expect(diagramContents).toContain("# comments in YAML shouldn't be removed");
456458
expect(diagramContents).toContain("flowchart TD\n A[I've been updated!]");
457459
}
458460
});
@@ -521,6 +523,11 @@ describe('push', () => {
521523
code: expect.not.stringContaining('id:'),
522524
}),
523525
);
526+
expect(vi.mocked(MermaidChart.prototype.setDocument)).toHaveBeenCalledWith(
527+
expect.objectContaining({
528+
code: expect.stringMatching(/^# This comment should be pushed to the server/m),
529+
}),
530+
);
524531
});
525532

526533
it('should push documents from within markdown file', async () => {

‎packages/cli/src/frontmatter.ts

+20-37
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
/**
22
* Copied from https://github.com/mermaid-js/mermaid/blob/4a4e614b646bdb5f91f02d0483a7704b315d09fd/packages/mermaid/src/diagram-api/regexes.ts
33
*/
4-
5-
// The "* as yaml" part is necessary for tree-shaking
6-
import * as yaml from 'js-yaml';
4+
import { parseDocument, type Document, YAMLMap, isMap } from 'yaml';
75

86
const frontMatterRegex = /^-{3}\s*[\n\r](.*?)[\n\r]-{3}\s*[\n\r]+/s;
97
const urlIDRegex = /(?<baseURL>.*)\/d\/(?<documentID>[\w-]+)/;
@@ -59,20 +57,13 @@ function splitFrontMatter(text: string) {
5957
}
6058
}
6159

62-
function parseFrontMatterYAML(frontMatterYaml: string) {
63-
let parsed: FrontMatterMetadata =
64-
// TODO: replace with https://www.npmjs.com/package/yaml so that we can
65-
// read/write comments too
66-
yaml.load(frontMatterYaml, {
67-
// To support config, we need JSON schema.
68-
// https://www.yaml.org/spec/1.2/spec.html#id2803231
69-
schema: yaml.JSON_SCHEMA,
70-
}) ?? {};
71-
72-
// To handle runtime data type changes
73-
parsed = typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
60+
function parseFrontMatterYAML(frontMatterYaml: string): Document<YAMLMap, false> {
61+
const document: Document = parseDocument(frontMatterYaml);
62+
if (!isMap(document.contents)) {
63+
document.contents = new YAMLMap();
64+
}
7465

75-
return parsed;
66+
return document as unknown as Document<YAMLMap, false>;
7667
}
7768

7869
/**
@@ -85,7 +76,7 @@ function parseFrontMatterYAML(frontMatterYaml: string) {
8576
export function extractFrontMatter(text: string): FrontMatterResult {
8677
const { diagramText, frontMatter } = splitFrontMatter(text);
8778

88-
const parsed = parseFrontMatterYAML(frontMatter);
79+
const parsed = parseFrontMatterYAML(frontMatter).toJSON();
8980

9081
const metadata: FrontMatterMetadata = {};
9182

@@ -116,16 +107,16 @@ export function extractFrontMatter(text: string): FrontMatterResult {
116107
* @param newMetadata - The metadata fields to update.
117108
* @returns The text with the updated YAML frontmatter.
118109
*/
119-
export function injectFrontMatter(text: string, newMetadata: Partial<FrontMatterMetadata>) {
110+
export function injectFrontMatter(text: string, newMetadata: Pick<FrontMatterMetadata, 'id'>) {
120111
const { diagramText, frontMatter } = splitFrontMatter(text);
121112

122-
const parsed = parseFrontMatterYAML(frontMatter);
113+
const document = parseFrontMatterYAML(frontMatter);
123114

124-
const mergedFrontmatter = { ...parsed, ...newMetadata };
115+
for (const [key, value] of Object.entries(newMetadata)) {
116+
document.contents.set(key, value);
117+
}
125118

126-
return `---\n${yaml.dump(mergedFrontmatter, {
127-
schema: yaml.JSON_SCHEMA,
128-
})}---\n${diagramText}`;
119+
return `---\n${document.toString()}---\n${diagramText}`;
129120
}
130121

131122
/**
@@ -138,24 +129,16 @@ export function injectFrontMatter(text: string, newMetadata: Partial<FrontMatter
138129
export function removeFrontMatterKeys(text: string, keysToRemove: Set<keyof FrontMatterMetadata>) {
139130
const { diagramText, frontMatter } = splitFrontMatter(text);
140131

141-
const parsedFrontMatter = parseFrontMatterYAML(frontMatter);
132+
const document = parseFrontMatterYAML(frontMatter);
142133

143-
const entries = Object.entries(parsedFrontMatter)
144-
.map((val) => {
145-
if (keysToRemove.has(val[0] as keyof FrontMatterMetadata)) {
146-
return null;
147-
} else {
148-
return val;
149-
}
150-
})
151-
.filter((val) => val) as [string, any][]; // eslint-disable-line @typescript-eslint/no-explicit-any
134+
for (const key of keysToRemove) {
135+
document.contents.delete(key);
136+
}
152137

153-
if (entries.length === 0) {
138+
if (document.contents.items.length === 0) {
154139
// skip creating frontmatter if there is no frontmatter
155140
return diagramText;
156141
} else {
157-
return `---\n${yaml.dump(Object.fromEntries(entries), {
158-
schema: yaml.JSON_SCHEMA,
159-
})}---\n${diagramText}`;
142+
return `---\n${document.toString()}---\n${diagramText}`;
160143
}
161144
}

‎packages/cli/test/fixtures/connected-diagram.mmd

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
2+
# This comment should be pushed to the server
23
title: My cool flowchart
34
id: https://test.mermaidchart.invalid/d/my-test-document-id
45
---

‎pnpm-lock.yaml

+19-15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Failed to load comments.