Skip to content

Commit 7d61290

Browse files
authored
Fix frontmatter validation to handle liquid variables (#57011)
1 parent c82c0a1 commit 7d61290

File tree

2 files changed

+84
-3
lines changed

2 files changed

+84
-3
lines changed

src/content-linter/lib/linting-rules/frontmatter-validation.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { addError } from 'markdownlint-rule-helpers'
22
import { getFrontmatter } from '@/content-linter/lib/helpers/utils'
33

4+
// Strip liquid tags from text for character counting purposes
5+
function stripLiquidTags(text) {
6+
if (typeof text !== 'string') return text
7+
// Remove both {% %} and {{ }} liquid tags
8+
return text.replace(/\{%.*?%\}/g, '').replace(/\{\{.*?\}\}/g, '')
9+
}
10+
411
export const frontmatterValidation = {
512
names: ['GHD055', 'frontmatter-validation'],
613
description:
@@ -75,12 +82,13 @@ export const frontmatterValidation = {
7582
}
7683

7784
// Cross-property validation: if title is longer than shortTitle limit, shortTitle must exist
78-
if (fm.title && fm.title.length > rules.shortTitle.max && !fm.shortTitle) {
85+
const strippedTitle = stripLiquidTags(fm.title)
86+
if (fm.title && strippedTitle.length > rules.shortTitle.max && !fm.shortTitle) {
7987
const titleLine = findPropertyLine(params.lines, 'title')
8088
addError(
8189
onError,
8290
titleLine,
83-
`Title is ${fm.title.length} characters, which exceeds the shortTitle limit of ${rules.shortTitle.max} characters. A shortTitle must be provided.`,
91+
`Title is ${strippedTitle.length} characters, which exceeds the shortTitle limit of ${rules.shortTitle.max} characters. A shortTitle must be provided.`,
8492
fm.title,
8593
null,
8694
null,
@@ -108,7 +116,8 @@ export const frontmatterValidation = {
108116
}
109117

110118
function validatePropertyLength(onError, lines, propertyName, propertyValue, limits, displayName) {
111-
const propertyLength = propertyValue.length
119+
const strippedValue = stripLiquidTags(propertyValue)
120+
const propertyLength = strippedValue.length
112121
const propertyLine = findPropertyLine(lines, propertyName)
113122

114123
// Only report the most severe error - maximum takes precedence over recommended

src/content-linter/tests/unit/frontmatter-validation.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,4 +501,76 @@ topics:
501501
})
502502
expect(articleResult['content/section/article.md']).toEqual([])
503503
})
504+
505+
// Liquid variable handling tests
506+
test('title with liquid variables counts characters correctly', async () => {
507+
const markdown = `---
508+
title: 'Getting started with {% data variables.product.prodname_github %}'
509+
topics:
510+
- GitHub
511+
---
512+
# Content
513+
`
514+
const result = await runRule(frontmatterValidation, {
515+
strings: { 'content/section/article.md': markdown },
516+
...fmOptions,
517+
})
518+
// 'Getting started with ' (21 chars) + liquid tag (0 chars) = 21 chars, should pass
519+
expect(result['content/section/article.md']).toEqual([])
520+
})
521+
522+
test('intro with liquid variables counts characters correctly', async () => {
523+
const markdown = `---
524+
title: 'Article title'
525+
intro: 'Learn how to use {% data variables.product.prodname_copilot %} for {{ something }}'
526+
topics:
527+
- GitHub
528+
---
529+
# Content
530+
`
531+
const result = await runRule(frontmatterValidation, {
532+
strings: { 'content/section/article.md': markdown },
533+
...fmOptions,
534+
})
535+
// 'Learn how to use for ' (21 chars) should pass
536+
expect(result['content/section/article.md']).toEqual([])
537+
})
538+
539+
test('shortTitle with liquid variables counts characters correctly', async () => {
540+
const markdown = `---
541+
title: 'This article title is exactly fifty characters!!!!'
542+
shortTitle: '{% data variables.product.prodname_copilot_short %}'
543+
topics:
544+
- GitHub
545+
---
546+
# Content
547+
`
548+
const result = await runRule(frontmatterValidation, {
549+
strings: { 'content/section/article.md': markdown },
550+
...fmOptions,
551+
})
552+
// Liquid tag should count as 0 characters, should pass
553+
expect(result['content/section/article.md']).toEqual([])
554+
})
555+
556+
test('long text with liquid variables still fails when limit exceeded', async () => {
557+
const longText = 'A'.repeat(70) // 70 chars
558+
const markdown = `---
559+
title: '${longText} {% data variables.product.prodname_github %} extra text'
560+
shortTitle: 'Short title'
561+
topics:
562+
- GitHub
563+
---
564+
# Content
565+
`
566+
const result = await runRule(frontmatterValidation, {
567+
strings: { 'content/section/article.md': markdown },
568+
...fmOptions,
569+
})
570+
// 70 A's + 1 space + 0 (liquid tag) + 1 space + 10 ('extra text') = 82 chars, should exceed 80 char limit for articles
571+
expect(result['content/section/article.md']).toHaveLength(1)
572+
expect(result['content/section/article.md'][0].errorDetail).toContain(
573+
'exceeds maximum length of 80 characters',
574+
)
575+
})
504576
})

0 commit comments

Comments
 (0)