Files
posthog.com/scripts/fix-mdx.js
Vincent (Wen Yu) Ge 343d4788b5 Lints changed MDX for common issues that upset gatsby (#12797)
Co-authored-by: Edwin Lim <edwin@posthog.com>
Co-authored-by: Eli Kinsey <eli@ekinsey.dev>
2025-09-17 17:39:05 -04:00

169 lines
4.5 KiB
JavaScript

#!/usr/bin/env node
const fs = require('fs') // eslint-disable-line @typescript-eslint/no-var-requires
const glob = require('glob') // eslint-disable-line @typescript-eslint/no-var-requires
// Components that should be excluded from spacing rules
const EXCEPTED_COMPONENTS = ['CallToAction']
function isExceptedComponent(line) {
return EXCEPTED_COMPONENTS.some((component) => line.includes(component))
}
function normalizeIndentation(lines) {
const result = []
let inCodeBlock = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
const trimmedLine = line.trim()
// Check for code block boundaries
if (trimmedLine.startsWith('```')) {
inCodeBlock = !inCodeBlock
result.push(line)
continue
}
// If inside code block, preserve original formatting
if (inCodeBlock) {
result.push(line)
continue
}
// Empty lines get no indentation
if (trimmedLine === '') {
result.push('')
continue
}
// Never indent - just use trimmed line
result.push(trimmedLine)
}
return result
}
function removeMultipleEmptyLines(lines) {
return lines.filter((line, index) => {
if (line.trim() === '' && index > 0 && lines[index - 1].trim() === '') {
return false
}
return true
})
}
function addEmptyLineBeforeClosingTags(lines) {
const result = []
let inCodeBlock = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
const trimmedLine = line.trim()
// Check for code block boundaries
if (trimmedLine.startsWith('```')) {
inCodeBlock = !inCodeBlock
result.push(line)
continue
}
// Skip if inside code block
if (inCodeBlock) {
result.push(line)
continue
}
const hasClosingJsxTag = /^<\/[^>]+>$/.test(trimmedLine)
const isExcepted = isExceptedComponent(trimmedLine)
if (hasClosingJsxTag && !isExcepted && result.length > 0 && result[result.length - 1].trim() !== '') {
result.push('')
}
result.push(line)
}
return result
}
function addEmptyLineAfterOpeningTags(lines) {
const result = []
let inCodeBlock = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
const trimmedLine = line.trim()
// Check for code block boundaries
if (trimmedLine.startsWith('```')) {
inCodeBlock = !inCodeBlock
result.push(line)
continue
}
result.push(line)
// Skip if inside code block
if (inCodeBlock) {
continue
}
const isHeader = /^#{1,6}\s/.test(trimmedLine)
const hasSelfClosingJsxTag = /^<[^/\s>]+[^>]*\/>$/.test(trimmedLine)
const hasOpeningJsxTag = /^<[^/\s>]+[^>]*>$/.test(trimmedLine) && !hasSelfClosingJsxTag
const isExcepted = isExceptedComponent(trimmedLine)
if ((hasOpeningJsxTag || hasSelfClosingJsxTag || isHeader) && !isExcepted && i < lines.length - 1) {
const nextLine = lines[i + 1]
if (nextLine !== undefined && nextLine.trim() !== '') {
result.push('')
}
}
}
return result
}
const RULES = [
normalizeIndentation,
removeMultipleEmptyLines,
addEmptyLineBeforeClosingTags,
addEmptyLineAfterOpeningTags,
]
function enforceSpacingRules(content) {
let lines = content.split('\n')
for (const rule of RULES) {
lines = rule(lines)
}
return lines.join('\n')
}
function processFile(filePath) {
const content = fs.readFileSync(filePath, 'utf8')
const correctedContent = enforceSpacingRules(content)
if (content !== correctedContent) {
fs.writeFileSync(filePath, correctedContent)
}
}
// Get file patterns from command line args or default to MDX files
const patterns = process.argv.slice(2)
if (patterns.length === 0) {
console.error('Error: Please specify file patterns or paths to process.')
console.error('Examples:')
console.error(' node scripts/lint-jsx-spacing.js "contents/docs/feature-flags/*.mdx"')
console.error(' node scripts/lint-jsx-spacing.js contents/docs/feature-flags/*.md')
process.exit(1)
}
console.log('=== The magical MDX fixer ===')
patterns.forEach((pattern) => {
const files = glob.sync(pattern)
files.forEach(processFile)
})
console.log('=== No more gatsby 404s! ===')