Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
11 changes: 10 additions & 1 deletion packages/opencode/src/config/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Filesystem } from "../util/filesystem"
export namespace ConfigMarkdown {
export const FILE_REGEX = /(?<![\w`])@(\.?[^\s`,.]*(?:\.[^\s`,.]+)*)/g
export const SHELL_REGEX = /!`([^`]+)`/g
export const UNQUOTED_HEX_FRONTMATTER_REGEX =
/^---\r?\n[\s\S]*?^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*:\s*#[0-9a-fA-F]{6}\s*$/m

export function files(template: string) {
return Array.from(template.matchAll(FILE_REGEX))
Expand Down Expand Up @@ -54,6 +56,12 @@ export namespace ConfigMarkdown {
continue
}

// quote unquoted hex colors because YAML treats #... as a comment
if (value.match(/^#[0-9a-fA-F]{6}$/)) {
result.push(`${key}: "${value}"`)
continue
}

// if value contains a colon, convert to block scalar
if (value.includes(":")) {
result.push(`${key}: |-`)
Expand All @@ -70,9 +78,10 @@ export namespace ConfigMarkdown {

export async function parse(filePath: string) {
const template = await Filesystem.readText(filePath)
const shouldUseFallback = UNQUOTED_HEX_FRONTMATTER_REGEX.test(template)

try {
const md = matter(template)
const md = matter(shouldUseFallback ? fallbackSanitization(template) : template)
return md
} catch {
try {
Expand Down
49 changes: 48 additions & 1 deletion packages/opencode/test/config/markdown.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { expect, test, describe } from "bun:test"
import { afterAll, beforeAll, expect, test, describe } from "bun:test"
import { mkdtemp, rm, writeFile } from "node:fs/promises"
import { tmpdir } from "node:os"
import path from "node:path"
import { ConfigMarkdown } from "../../src/config/markdown"

describe("ConfigMarkdown: normal template", () => {
Expand Down Expand Up @@ -226,3 +229,47 @@ describe("ConfigMarkdown: frontmatter has weird model id", async () => {
expect(result.content.trim()).toBe("Strictly follow da rules")
})
})

describe("ConfigMarkdown: frontmatter parsing w/ hex colors", () => {
let dir: string

beforeAll(async () => {
dir = await mkdtemp(path.join(tmpdir(), "opencode-markdown-"))

await writeFile(
path.join(dir, "quoted-hex.md"),
`---
name: Quoted Hex
color: "#008080"
---

Content
`,
)

await writeFile(
path.join(dir, "unquoted-hex.md"),
`---
name: Unquoted Hex
color: #008080
---

Content
`,
)
})

afterAll(async () => {
await rm(dir, { recursive: true, force: true })
})

test("should preserve quoted hex colors", async () => {
const result = await ConfigMarkdown.parse(path.join(dir, "quoted-hex.md"))
expect(result.data.color).toBe("#008080")
})

test("should recover unquoted hex colors that YAML treats as comments", async () => {
const result = await ConfigMarkdown.parse(path.join(dir, "unquoted-hex.md"))
expect(result.data.color).toBe("#008080")
})
})
Loading