diff --git a/lib/blog.ts b/lib/blog.ts index a1e21fe8..0715f75a 100644 --- a/lib/blog.ts +++ b/lib/blog.ts @@ -65,11 +65,8 @@ export async function getPostBySlug(slug: string, locale: string): Promise { - return 'data="{' + p1.replace(/"/g, '"') + '}"'; - }); + const { fixMdxDataProps } = await import('./mdx-utils'); + const fixedContent = fixMdxDataProps(content); let parsedContent = fixedContent; try { diff --git a/lib/mdx-utils.ts b/lib/mdx-utils.ts new file mode 100644 index 00000000..4f3ee4c0 --- /dev/null +++ b/lib/mdx-utils.ts @@ -0,0 +1,46 @@ +export function fixMdxDataProps(content: string): string { + let fixedContent = content; + let dataIndex = fixedContent.indexOf('data={{'); + + while (dataIndex !== -1) { + let openCount = 0; + let endIndex = -1; + const startObj = dataIndex + 6; // index of the first '{' in 'data={{' + + for (let i = startObj; i < fixedContent.length; i++) { + if (fixedContent[i] === '{') { + openCount++; + } else if (fixedContent[i] === '}') { + openCount--; + if (openCount === 0) { + endIndex = i; + break; + } + } + } + + if (endIndex !== -1) { + // jsonStr is the content INSIDE the outer curly braces + const jsonStr = fixedContent.substring(startObj + 1, endIndex); + const safeJsonStr = jsonStr.replace(/"/g, '"'); + const replacement = `data="{${safeJsonStr}}"`; + + // We also need to consume the closing `}` of the `data={{` + const nextCharIndex = endIndex + 1; + const skipChars = + nextCharIndex < fixedContent.length && fixedContent[nextCharIndex] === '}' ? 2 : 1; + + fixedContent = + fixedContent.substring(0, dataIndex) + + replacement + + fixedContent.substring(endIndex + skipChars); + + dataIndex = fixedContent.indexOf('data={{', dataIndex + replacement.length); + } else { + // Malformed braces, prevent infinite loop + break; + } + } + + return fixedContent; +} diff --git a/lib/pages.ts b/lib/pages.ts index 79464694..e3b17639 100644 --- a/lib/pages.ts +++ b/lib/pages.ts @@ -53,11 +53,8 @@ export async function getPageBySlug(slug: string, locale: string): Promise { - return 'data="{' + p1.replace(/"/g, '"') + '}"'; - }); + const { fixMdxDataProps } = await import('./mdx-utils'); + const fixedContent = fixMdxDataProps(content); let parsedContent = fixedContent; try { diff --git a/lib/products.ts b/lib/products.ts index 7e901a3a..ceccc145 100644 --- a/lib/products.ts +++ b/lib/products.ts @@ -39,11 +39,8 @@ export async function getProductBySlug(slug: string, locale: string): Promise { - return 'data="{' + p1.replace(/"/g, '"') + '}"'; - }); + const { fixMdxDataProps } = await import('./mdx-utils'); + const fixedContent = fixMdxDataProps(content); let parsedContent = fixedContent; try { diff --git a/sentry.edge.config.ts b/sentry.edge.config.ts index 7b2a127f..4a40412d 100644 --- a/sentry.edge.config.ts +++ b/sentry.edge.config.ts @@ -12,4 +12,5 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, + ignoreErrors: ['failed to pipe response'], }); diff --git a/sentry.server.config.ts b/sentry.server.config.ts index 7b2a127f..4a40412d 100644 --- a/sentry.server.config.ts +++ b/sentry.server.config.ts @@ -12,4 +12,5 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, + ignoreErrors: ['failed to pipe response'], }); diff --git a/tests/mdx-regex.test.ts b/tests/mdx-regex.test.ts new file mode 100644 index 00000000..9262a21c --- /dev/null +++ b/tests/mdx-regex.test.ts @@ -0,0 +1,17 @@ +import { describe, it, expect } from 'vitest'; +import { fixMdxDataProps } from '../lib/mdx-utils'; + +describe('MDX Data Props Fixer', () => { + it('should correctly parse MDX with nested JSON containing }}', () => { + // This string simulates the exact structure that causes the bug in n2x2y.mdx + const mdxInput = ``; + + const result = fixMdxDataProps(mdxInput); + + // The expected output should have the entire JSON object enclosed in data="{...}" + // and NO trailing characters left over from the regex truncating early. + const expected = ``; + + expect(result).toBe(expected); + }); +});