diff --git a/.changeset/unlucky-wasps-refuse.md b/.changeset/unlucky-wasps-refuse.md new file mode 100644 index 000000000000..5e0d4d664be2 --- /dev/null +++ b/.changeset/unlucky-wasps-refuse.md @@ -0,0 +1,5 @@ +--- +'@astrojs/markdown-remark': patch +--- + +Fixes frontmatter parsing if file is encoded in UTF8 with BOM diff --git a/packages/markdown/remark/src/frontmatter.ts b/packages/markdown/remark/src/frontmatter.ts index 94fbec2b3312..fe878df662b5 100644 --- a/packages/markdown/remark/src/frontmatter.ts +++ b/packages/markdown/remark/src/frontmatter.ts @@ -11,9 +11,10 @@ export function isFrontmatterValid(frontmatter: Record) { } // Capture frontmatter wrapped with `---`, including any characters and new lines within it. -// Only capture if it exists near the top of the file (whitespaces between the start of file and -// the start of `---` are allowed) -const frontmatterRE = /^\s*---([\s\S]*?\n)---/; +// Only capture if `---` exists near the top of the file, including: +// 1. Start of file (including if has BOM encoding) +// 2. Start of file with any whitespace (but `---` must still start on a new line) +const frontmatterRE = /(?:^\uFEFF?|^\s*\n)---([\s\S]*?\n)---/; export function extractFrontmatter(code: string): string | undefined { return frontmatterRE.exec(code)?.[1]; } diff --git a/packages/markdown/remark/test/frontmatter.test.js b/packages/markdown/remark/test/frontmatter.test.js index 6a8b6b37ca47..155368e59f2e 100644 --- a/packages/markdown/remark/test/frontmatter.test.js +++ b/packages/markdown/remark/test/frontmatter.test.js @@ -2,16 +2,21 @@ import assert from 'node:assert/strict'; import { describe, it } from 'node:test'; import { extractFrontmatter, parseFrontmatter } from '../dist/index.js'; +const bom = '\uFEFF'; + describe('extractFrontmatter', () => { it('works', () => { const yaml = `\nfoo: bar\n`; assert.equal(extractFrontmatter(`---${yaml}---`), yaml); - assert.equal(extractFrontmatter(` ---${yaml}---`), yaml); + assert.equal(extractFrontmatter(`${bom}---${yaml}---`), yaml); assert.equal(extractFrontmatter(`\n---${yaml}---`), yaml); assert.equal(extractFrontmatter(`\n \n---${yaml}---`), yaml); assert.equal(extractFrontmatter(`---${yaml}---\ncontent`), yaml); + assert.equal(extractFrontmatter(`${bom}---${yaml}---\ncontent`), yaml); assert.equal(extractFrontmatter(`\n\n---${yaml}---\n\ncontent`), yaml); assert.equal(extractFrontmatter(`\n \n---${yaml}---\n\ncontent`), yaml); + assert.equal(extractFrontmatter(` ---${yaml}---`), undefined); + assert.equal(extractFrontmatter(`---${yaml} ---`), undefined); assert.equal(extractFrontmatter(`text\n---${yaml}---\n\ncontent`), undefined); }); }); @@ -24,10 +29,10 @@ describe('parseFrontmatter', () => { rawFrontmatter: yaml, content: '', }); - assert.deepEqual(parseFrontmatter(` ---${yaml}---`), { + assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---`), { frontmatter: { foo: 'bar' }, rawFrontmatter: yaml, - content: ' ', + content: bom, }); assert.deepEqual(parseFrontmatter(`\n---${yaml}---`), { frontmatter: { foo: 'bar' }, @@ -44,6 +49,11 @@ describe('parseFrontmatter', () => { rawFrontmatter: yaml, content: '\ncontent', }); + assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---\ncontent`), { + frontmatter: { foo: 'bar' }, + rawFrontmatter: yaml, + content: `${bom}\ncontent`, + }); assert.deepEqual(parseFrontmatter(`\n\n---${yaml}---\n\ncontent`), { frontmatter: { foo: 'bar' }, rawFrontmatter: yaml, @@ -54,6 +64,16 @@ describe('parseFrontmatter', () => { rawFrontmatter: yaml, content: '\n \n\n\ncontent', }); + assert.deepEqual(parseFrontmatter(` ---${yaml}---`), { + frontmatter: {}, + rawFrontmatter: '', + content: ` ---${yaml}---`, + }); + assert.deepEqual(parseFrontmatter(`---${yaml} ---`), { + frontmatter: {}, + rawFrontmatter: '', + content: `---${yaml} ---`, + }); assert.deepEqual(parseFrontmatter(`text\n---${yaml}---\n\ncontent`), { frontmatter: {}, rawFrontmatter: '',