Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for working with markdown front matter #642

Merged
merged 8 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion packages/core/src/frontmatter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, test } from "node:test"
import assert from "node:assert/strict"
import { frontmatterTryParse } from "./frontmatter"
import { frontmatterTryParse, splitMarkdown, updateFrontmatter } from "./frontmatter"

describe("replace frontmatter", () => {
test("only", () => {
Expand All @@ -21,3 +21,55 @@ foo bar
assert.deepEqual(res, { foo: "bar" })
})
})

describe("splitMarkdown", () => {
test("split markdown with yaml frontmatter", () => {
const markdown = `---
title: Test
---
This is a test.`
const { frontmatter, content } = splitMarkdown(markdown)
assert.deepEqual(frontmatter, { title: "Test" })
assert.equal(content, "This is a test.")
})

test("split markdown with json frontmatter", () => {
const markdown = `---
{
"title": "Test"
}
---
This is a test.`
const { frontmatter, content } = splitMarkdown(markdown, { format: "json" })
assert.deepEqual(frontmatter, { title: "Test" })
assert.equal(content, "This is a test.")
})
})

describe("updateFrontmatter", () => {
test("update yaml frontmatter", () => {
const markdown = `---
title: Old Title
---
This is a test.`
const newFrontmatter = { title: "New Title" }
const updatedMarkdown = updateFrontmatter(markdown, newFrontmatter)
const { frontmatter, content } = splitMarkdown(updatedMarkdown)
assert.deepEqual(frontmatter, { title: "New Title" })
assert.equal(content, "This is a test.")
})

test("update json frontmatter", () => {
const markdown = `---
{
"title": "Old Title"
}
---
This is a test.`
const newFrontmatter = { title: "New Title" }
const updatedMarkdown = updateFrontmatter(markdown, newFrontmatter, { format: "json" })
const { frontmatter, content } = splitMarkdown(updatedMarkdown, { format: "json" })
assert.deepEqual(frontmatter, { title: "New Title" })
assert.equal(content, "This is a test.")
})
})
32 changes: 31 additions & 1 deletion packages/core/src/frontmatter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JSON5TryParse } from "./json5"
import { TOMLTryParse } from "./toml"
import { YAMLTryParse } from "./yaml"
import { YAMLTryParse, YAMLStringify } from "./yaml"

export function frontmatterTryParse(
text: string,
Expand Down Expand Up @@ -34,3 +34,33 @@
}
return res !== undefined ? { end: end + 1, value: res } : undefined
}

export function splitMarkdown(
text: string,
options?: { format: "yaml" | "json" | "toml" }
): { frontmatter: any; content: string } {
const { value: frontmatter, end } = frontmatterTryParse(text, options) || {}
const content = end ? text.split(/\r?\n/g).slice(end).join("\n") : text
return { frontmatter, content }
}

Check failure on line 45 in packages/core/src/frontmatter.ts

View workflow job for this annotation

GitHub Actions / build

There is no null check for the `frontmatterTryParse` function result. If this function returns null or undefined, it could lead to a runtime error when trying to destructure `value` and `end`. Consider adding a null check before destructuring the result. 🛠️
pelikhan marked this conversation as resolved.
Show resolved Hide resolved

export function updateFrontmatter(
text: string,
newFrontmatter: any,
options?: { format: "yaml" | "json" }
): string {
const { format = "yaml" } = options || {}
const { content } = splitMarkdown(text, options)
let fm: string
switch (format) {
case "json":
fm = JSON.stringify(newFrontmatter, null, 2)
pelikhan marked this conversation as resolved.
Show resolved Hide resolved
break
case "yaml":
fm = YAMLStringify(newFrontmatter)
break
default:
throw new Error(`Unsupported format: ${format}`)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default case in the switch statement throws an error for unsupported formats. However, the function does not handle this error, which could lead to unhandled exceptions. Consider providing a default format or handling this error in a way that does not interrupt the execution of the program. 😊

generated by pr-review-commit unsupported_format

}
return `---\n${fm}\n---\n${content}`

Check failure on line 65 in packages/core/src/frontmatter.ts

View workflow job for this annotation

GitHub Actions / build

There is no error handling for the case when the `format` is not "json" or "yaml". This could lead to unexpected behavior if an unsupported format is passed. Consider adding error handling or a default case to handle unsupported formats. 🛠️
pelikhan marked this conversation as resolved.
Show resolved Hide resolved
}
11 changes: 11 additions & 0 deletions packages/core/src/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { randomHex } from "./crypto"
import { extractFenced } from "./fence"
import { trimNewlines } from "./util"
import { splitMarkdown, updateFrontmatter } from "./frontmatter"

export function prettifyMarkdown(md: string) {
let res = md
Expand Down Expand Up @@ -138,3 +139,13 @@
return details(node.label, node.content.map(renderTraceTree).join("\n"))
else return ""
}

export function mergeFrontmatter(
text: string,
newFrontmatter: any,
options?: { format: "yaml" | "json" }
): string {
const { frontmatter, content } = splitMarkdown(text, options)
pelikhan marked this conversation as resolved.
Show resolved Hide resolved
const updatedFrontmatter = { ...frontmatter, ...newFrontmatter }
return updateFrontmatter(text, updatedFrontmatter, options)

Check failure on line 150 in packages/core/src/markdown.ts

View workflow job for this annotation

GitHub Actions / build

There is no null check for the `splitMarkdown` function result. If this function returns null or undefined, it could lead to a runtime error when trying to destructure `frontmatter` and `content`. Consider adding a null check before destructuring the result. 🛠️

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no null check for the splitMarkdown function result. If this function returns null or undefined, it could lead to a runtime error when trying to destructure frontmatter and content. Consider adding a null check before destructuring the result. 🛠️

generated by pr-review-commit missing_null_check

}
1 change: 1 addition & 0 deletions packages/core/src/toml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export function TOMLTryParse(text: string, options?: { defaultValue?: any }) {
return options?.defaultValue
}
}

Loading