Skip to content

Commit f0249ac

Browse files
committed
test: add tests for parse-basic-frontmatter
1 parent 704987b commit f0249ac

File tree

2 files changed

+130
-25
lines changed

2 files changed

+130
-25
lines changed

shared/utils/parse-basic-frontmatter.ts

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,30 @@ export function parseBasicFrontmatter(fileContent: string): Record<string, unkno
22
const match = fileContent.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/)
33
if (!match?.[1]) return {}
44

5-
return match[1].split('\n').reduce(
6-
(acc, line) => {
7-
const idx = line.indexOf(':')
8-
if (idx === -1) return acc
5+
return match[1].split('\n').reduce<Record<string, unknown>>((acc, line) => {
6+
const idx = line.indexOf(':')
7+
if (idx === -1) return acc
98

10-
const key = line.slice(0, idx).trim()
9+
const key = line.slice(0, idx).trim()
1110

12-
// Remove surrounding quotes
13-
let value = line
14-
.slice(idx + 1)
15-
.trim()
16-
.replace(/^["']|["']$/g, '')
11+
// Remove surrounding quotes
12+
let value = line
13+
.slice(idx + 1)
14+
.trim()
15+
.replace(/^["']|["']$/g, '')
1716

18-
// Type coercion (handles 123, 45.6, boolean, arrays)
19-
if (value === 'true') acc[key] = true
20-
else if (value === 'false') acc[key] = false
21-
else if (/^-?\d+$/.test(value)) acc[key] = parseInt(value, 10)
22-
else if (/^-?\d+\.\d+$/.test(value)) acc[key] = parseFloat(value)
23-
else if (value.startsWith('[') && value.endsWith(']')) {
24-
acc[key] = value
25-
.slice(1, -1)
26-
.split(',')
27-
.map(s => s.trim().replace(/^["']|["']$/g, ''))
28-
} else acc[key] = value
17+
// Type coercion (handles 123, 45.6, boolean, arrays)
18+
if (value === 'true') acc[key] = true
19+
else if (value === 'false') acc[key] = false
20+
else if (/^-?\d+$/.test(value)) acc[key] = parseInt(value, 10)
21+
else if (/^-?\d+\.\d+$/.test(value)) acc[key] = parseFloat(value)
22+
else if (value.startsWith('[') && value.endsWith(']')) {
23+
acc[key] = value
24+
.slice(1, -1)
25+
.split(',')
26+
.map(s => s.trim().replace(/^["']|["']$/g, ''))
27+
} else acc[key] = value
2928

30-
return acc
31-
},
32-
{} as Record<string, unknown>,
33-
)
29+
return acc
30+
}, {})
3431
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { parseBasicFrontmatter } from '../../../../shared/utils/parse-basic-frontmatter'
3+
4+
describe('parseBasicFrontmatter', () => {
5+
it('returns empty object for content without frontmatter', () => {
6+
expect(parseBasicFrontmatter('just some text')).toEqual({})
7+
})
8+
9+
it('returns empty object for empty string', () => {
10+
expect(parseBasicFrontmatter('')).toEqual({})
11+
})
12+
13+
it('returns empty object for empty frontmatter block', () => {
14+
expect(parseBasicFrontmatter('---\n---\n')).toEqual({})
15+
})
16+
17+
it('parses string values', () => {
18+
const input = '---\ntitle: Hello World\nauthor: James\n---\n'
19+
expect(parseBasicFrontmatter(input)).toEqual({
20+
title: 'Hello World',
21+
author: 'James',
22+
})
23+
})
24+
25+
it('strips surrounding quotes from values', () => {
26+
const input = '---\ntitle: "Hello World"\nauthor: \'James\'\n---\n'
27+
expect(parseBasicFrontmatter(input)).toEqual({
28+
title: 'Hello World',
29+
author: 'James',
30+
})
31+
})
32+
33+
it('parses boolean true', () => {
34+
const input = '---\ndraft: true\n---\n'
35+
expect(parseBasicFrontmatter(input)).toEqual({ draft: true })
36+
})
37+
38+
it('parses boolean false', () => {
39+
const input = '---\ndraft: false\n---\n'
40+
expect(parseBasicFrontmatter(input)).toEqual({ draft: false })
41+
})
42+
43+
it('parses integer values', () => {
44+
const input = '---\ncount: 42\nnegative: -7\n---\n'
45+
expect(parseBasicFrontmatter(input)).toEqual({ count: 42, negative: -7 })
46+
})
47+
48+
it('parses float values', () => {
49+
const input = '---\nrating: 4.5\nnegative: -3.14\n---\n'
50+
expect(parseBasicFrontmatter(input)).toEqual({ rating: 4.5, negative: -3.14 })
51+
})
52+
53+
it('parses array values', () => {
54+
const input = '---\ntags: [foo, bar, baz]\n---\n'
55+
expect(parseBasicFrontmatter(input)).toEqual({
56+
tags: ['foo', 'bar', 'baz'],
57+
})
58+
})
59+
60+
it('strips quotes from array items', () => {
61+
const input = '---\ntags: ["foo", \'bar\']\n---\n'
62+
expect(parseBasicFrontmatter(input)).toEqual({
63+
tags: ['foo', 'bar'],
64+
})
65+
})
66+
67+
it('does not support nested arrays', () => {
68+
const input = '---\nmatrix: [[1, 2], [3, 4]]\n---\n'
69+
const result = parseBasicFrontmatter(input)
70+
expect(result.matrix).toEqual(['[1', '2]', '[3', '4]'])
71+
})
72+
73+
it('handles values with colons', () => {
74+
const input = '---\nurl: https://example.com\n---\n'
75+
expect(parseBasicFrontmatter(input)).toEqual({
76+
url: 'https://example.com',
77+
})
78+
})
79+
80+
it('skips lines without colons', () => {
81+
const input = '---\ntitle: Hello\ninvalid line\nauthor: James\n---\n'
82+
expect(parseBasicFrontmatter(input)).toEqual({
83+
title: 'Hello',
84+
author: 'James',
85+
})
86+
})
87+
88+
it('trims keys and values', () => {
89+
const input = '---\n title : Hello \n---\n'
90+
expect(parseBasicFrontmatter(input)).toEqual({ title: 'Hello' })
91+
})
92+
93+
it('handles frontmatter at end of file without trailing newline', () => {
94+
const input = '---\ntitle: Hello\n---'
95+
expect(parseBasicFrontmatter(input)).toEqual({ title: 'Hello' })
96+
})
97+
98+
it('handles mixed types', () => {
99+
const input = '---\ntitle: My Post\ncount: 5\nrating: 9.8\npublished: true\ntags: [a, b]\n---\n'
100+
expect(parseBasicFrontmatter(input)).toEqual({
101+
title: 'My Post',
102+
count: 5,
103+
rating: 9.8,
104+
published: true,
105+
tags: ['a', 'b'],
106+
})
107+
})
108+
})

0 commit comments

Comments
 (0)