mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-02 03:37:48 +02:00
fix(utils): allow any non-boundary characters in Markdown heading ID (#7604)
This commit is contained in:
parent
0114f00069
commit
89e146f596
3 changed files with 61 additions and 4 deletions
|
@ -833,6 +833,53 @@ describe('parseMarkdownHeadingId', () => {
|
||||||
id: 'id',
|
id: 'id',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not parse empty id', () => {
|
||||||
|
expect(parseMarkdownHeadingId('## a {#}')).toEqual({
|
||||||
|
text: '## a {#}',
|
||||||
|
id: undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can parse id with more characters', () => {
|
||||||
|
expect(parseMarkdownHeadingId('## a {#你好}')).toEqual({
|
||||||
|
text: '## a',
|
||||||
|
id: '你好',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseMarkdownHeadingId('## a {#2022.1.1}')).toEqual({
|
||||||
|
text: '## a',
|
||||||
|
id: '2022.1.1',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseMarkdownHeadingId('## a {#a#b}')).toEqual({
|
||||||
|
text: '## a',
|
||||||
|
id: 'a#b',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// The actual behavior is unspecified, just need to ensure it stays consistent
|
||||||
|
it('handles unmatched boundaries', () => {
|
||||||
|
expect(parseMarkdownHeadingId('## a {# a {#bcd}')).toEqual({
|
||||||
|
text: '## a {# a',
|
||||||
|
id: 'bcd',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseMarkdownHeadingId('## a {#bcd}}')).toEqual({
|
||||||
|
text: '## a {#bcd}}',
|
||||||
|
id: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseMarkdownHeadingId('## a {#b{cd}')).toEqual({
|
||||||
|
text: '## a',
|
||||||
|
id: 'b{cd',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(parseMarkdownHeadingId('## a {#b{#b}')).toEqual({
|
||||||
|
text: '## a {#b',
|
||||||
|
id: 'b',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('writeMarkdownHeadingId', () => {
|
describe('writeMarkdownHeadingId', () => {
|
||||||
|
|
|
@ -14,8 +14,8 @@ import {createSlugger, type Slugger, type SluggerOptions} from './slugger';
|
||||||
// content. Most parsing is still done in MDX through the mdx-loader.
|
// content. Most parsing is still done in MDX through the mdx-loader.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses custom ID from a heading. The ID must be composed of letters,
|
* Parses custom ID from a heading. The ID can contain any characters except
|
||||||
* underscores, and dashes only.
|
* `{#` and `}`.
|
||||||
*
|
*
|
||||||
* @param heading e.g. `## Some heading {#some-heading}` where the last
|
* @param heading e.g. `## Some heading {#some-heading}` where the last
|
||||||
* character must be `}` for the ID to be recognized
|
* character must be `}` for the ID to be recognized
|
||||||
|
@ -26,9 +26,9 @@ export function parseMarkdownHeadingId(heading: string): {
|
||||||
*/
|
*/
|
||||||
text: string;
|
text: string;
|
||||||
/** The heading ID. e.g. `some-heading` */
|
/** The heading ID. e.g. `some-heading` */
|
||||||
id?: string;
|
id: string | undefined;
|
||||||
} {
|
} {
|
||||||
const customHeadingIdRegex = /\s*\{#(?<id>[\w-]+)\}$/;
|
const customHeadingIdRegex = /\s*\{#(?<id>(?:.(?!\{#|\}))*.)\}$/;
|
||||||
const matches = customHeadingIdRegex.exec(heading);
|
const matches = customHeadingIdRegex.exec(heading);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -162,6 +162,16 @@ function Clock(props) {
|
||||||
|
|
||||||
## Custom heading ID {#custom}
|
## Custom heading ID {#custom}
|
||||||
|
|
||||||
|
### Weird heading {#你好}
|
||||||
|
|
||||||
|
### Weird heading {#2022.1.1}
|
||||||
|
|
||||||
|
### Weird heading {#a#b}
|
||||||
|
|
||||||
|
### Weird heading {#a b}
|
||||||
|
|
||||||
|
### Weird heading {#a{b}
|
||||||
|
|
||||||
## Pipe
|
## Pipe
|
||||||
|
|
||||||
Code tag + double pipe: <code>||</code>
|
Code tag + double pipe: <code>||</code>
|
||||||
|
|
Loading…
Add table
Reference in a new issue