Skip to content

Commit

Permalink
fix(utils): better handling of code blocks in link replacement (#9046)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josh-Cena committed Jun 8, 2023
1 parent dcce8ff commit 76f9203
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ exports[`replaceMarkdownLinks handles stray spaces 1`] = `
}
`;
exports[`replaceMarkdownLinks handles unpaired fences 1`] = `
{
"brokenMarkdownLinks": [],
"newContent": "
\`\`\`foo
hello
\`\`\`foo
hello
\`\`\`
A [link](/docs/file)
",
}
`;
exports[`replaceMarkdownLinks ignores links in HTML comments 1`] = `
{
"brokenMarkdownLinks": [
Expand Down
26 changes: 26 additions & 0 deletions packages/docusaurus-utils/src/__tests__/markdownLinks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,32 @@ The following operations are defined for [URI]s:
[URL](./file.md?foo=bar#baz)
[URL](./file.md#a)
[URL](./file.md?c)
`,
}),
).toMatchSnapshot();
});

it('handles unpaired fences', () => {
expect(
replaceMarkdownLinks({
siteDir: '.',
filePath: 'docs/file.md',
contentPaths: {
contentPath: 'docs',
contentPathLocalized: 'i18n/docs-localized',
},
sourceToPermalink: {
'@site/docs/file.md': '/docs/file',
},
fileString: `
\`\`\`foo
hello
\`\`\`foo
hello
\`\`\`
A [link](./file.md)
`,
}),
).toMatchSnapshot();
Expand Down
40 changes: 31 additions & 9 deletions packages/docusaurus-utils/src/markdownLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ export type BrokenMarkdownLink<T extends ContentPaths> = {
link: string;
};

type CodeFence = {
type: '`' | '~';
definitelyOpen: boolean;
count: number;
};

function parseCodeFence(line: string): CodeFence | null {
const match = line.trim().match(/^(?<fence>`{3,}|~{3,})(?<rest>.*)/);
if (!match) {
return null;
}
return {
type: match.groups!.fence![0]! as '`' | '~',
definitelyOpen: !!match.groups!.rest!,
count: match.groups!.fence!.length,
};
}

/**
* Takes a Markdown file and replaces relative file references with their URL
* counterparts, e.g. `[link](./intro.md)` => `[link](/docs/intro)`, preserving
Expand Down Expand Up @@ -82,19 +100,23 @@ export function replaceMarkdownLinks<T extends ContentPaths>({
const brokenMarkdownLinks: BrokenMarkdownLink<T>[] = [];

// Replace internal markdown linking (except in fenced blocks).
let lastCodeFence: string | null = null;
let lastOpenCodeFence: CodeFence | null = null;
const lines = fileString.split('\n').map((line) => {
const codeFence = line.trimStart().match(/^`{3,}|^~{3,}/)?.[0];
const codeFence = parseCodeFence(line);
if (codeFence) {
if (!lastCodeFence) {
lastCodeFence = codeFence;
// If we are in a ````-fenced block, all ``` would be plain text instead
// of fences
} else if (codeFence.startsWith(lastCodeFence)) {
lastCodeFence = null;
if (!lastOpenCodeFence) {
lastOpenCodeFence = codeFence;
} else if (
!codeFence.definitelyOpen &&
lastOpenCodeFence.type === codeFence.type &&
lastOpenCodeFence.count <= codeFence.count
) {
// All three conditions must be met in order for this to be considered
// a closing fence.
lastOpenCodeFence = null;
}
}
if (lastCodeFence) {
if (lastOpenCodeFence) {
return line;
}

Expand Down

0 comments on commit 76f9203

Please sign in to comment.