Update MD051/link-fragments to add the ignored_pattern configuration parameter (fixes #547).

This commit is contained in:
David Anson 2025-04-05 22:34:54 -07:00
parent 45932c7837
commit 02478d24cf
17 changed files with 297 additions and 4 deletions

View file

@ -74,6 +74,12 @@ And this link to content starting within line 19 running into line 21:
[Link](#L19C5-L21C11)
```
Some Markdown generators dynamically create and insert headings when building
documents, for example by combining a fixed prefix like `figure-` and an
incrementing numeric counter. To ignore such generated fragments, set the
`ignored_pattern` [regular expression][RegEx] parameter to a pattern that
matches (e.g., `^figure-`).
Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document.
@ -89,3 +95,4 @@ append an incrementing integer as needed for uniqueness.
[github-heading-algorithm]: https://github.com/gjtorikian/html-pipeline/blob/f13a1534cb650ba17af400d1acd3a22c28004c09/lib/html/pipeline/toc_filter.rb
[github-linking-to-content]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet#linking-to-markdown#linking-to-markdown
[html-top-fragment]: https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment
[RegEx]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions

View file

@ -2156,6 +2156,8 @@ Aliases: `link-fragments`
Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`)
- `ignored_pattern`: Pattern for ignoring additional fragments (`string`,
default ``)
Fixable: Some violations can be fixed by tooling
@ -2235,6 +2237,12 @@ And this link to content starting within line 19 running into line 21:
[Link](#L19C5-L21C11)
```
Some Markdown generators dynamically create and insert headings when building
documents, for example by combining a fixed prefix like `figure-` and an
incrementing numeric counter. To ignore such generated fragments, set the
`ignored_pattern` [regular expression][RegEx] parameter to a pattern that
matches (e.g., `^figure-`).
Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document.
@ -2250,6 +2258,7 @@ append an incrementing integer as needed for uniqueness.
[github-heading-algorithm]: https://github.com/gjtorikian/html-pipeline/blob/f13a1534cb650ba17af400d1acd3a22c28004c09/lib/html/pipeline/toc_filter.rb
[github-linking-to-content]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet#linking-to-markdown#linking-to-markdown
[html-top-fragment]: https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment
[RegEx]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions
<a name="md052"></a>

View file

@ -7,6 +7,8 @@ Aliases: `link-fragments`
Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`)
- `ignored_pattern`: Pattern for ignoring additional fragments (`string`,
default ``)
Fixable: Some violations can be fixed by tooling
@ -86,6 +88,12 @@ And this link to content starting within line 19 running into line 21:
[Link](#L19C5-L21C11)
```
Some Markdown generators dynamically create and insert headings when building
documents, for example by combining a fixed prefix like `figure-` and an
incrementing numeric counter. To ignore such generated fragments, set the
`ignored_pattern` [regular expression][RegEx] parameter to a pattern that
matches (e.g., `^figure-`).
Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document.
@ -101,3 +109,4 @@ append an incrementing integer as needed for uniqueness.
[github-heading-algorithm]: https://github.com/gjtorikian/html-pipeline/blob/f13a1534cb650ba17af400d1acd3a22c28004c09/lib/html/pipeline/toc_filter.rb
[github-linking-to-content]: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-a-permanent-link-to-a-code-snippet#linking-to-markdown#linking-to-markdown
[html-top-fragment]: https://html.spec.whatwg.org/multipage/browsing-the-web.html#scrolling-to-a-fragment
[RegEx]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions

View file

@ -970,6 +970,10 @@ export interface ConfigurationStrict {
* Ignore case of fragments
*/
ignore_case?: boolean;
/**
* Pattern for ignoring additional fragments
*/
ignored_pattern?: string;
};
/**
* MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md051.md
@ -981,6 +985,10 @@ export interface ConfigurationStrict {
* Ignore case of fragments
*/
ignore_case?: boolean;
/**
* Pattern for ignoring additional fragments
*/
ignored_pattern?: string;
};
/**
* MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md052.md

View file

@ -66,6 +66,8 @@ export default {
"parser": "micromark",
"function": function MD051(params, onError) {
const ignoreCase = params.config.ignore_case || false;
const ignoredPattern = params.config.ignored_pattern || "";
const ignoredPatternRe = new RegExp(ignoredPattern || "^$");
/** @type {Map<string, number>} */
const fragments = new Map([ [ "#top", 0 ] ]);
@ -114,12 +116,14 @@ export default {
for (const definition of definitions) {
const { endColumn, startColumn } = definition;
const text = unescapeStringTokenText(definition);
const encodedText = `#${encodeURIComponent(text.slice(1))}`;
const textSliceOne = text.slice(1);
const encodedText = `#${encodeURIComponent(textSliceOne)}`;
if (
(text.length > 1) &&
text.startsWith("#") &&
!fragments.has(encodedText) &&
!lineFragmentRe.test(encodedText)
!lineFragmentRe.test(encodedText) &&
!ignoredPatternRe.test(textSliceOne)
) {
let context = undefined;
let range = undefined;

View file

@ -268,7 +268,9 @@
// MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md051.md
"MD051": {
// Ignore case of fragments
"ignore_case": false
"ignore_case": false,
// Pattern for ignoring additional fragments
"ignored_pattern": ""
},
// MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md052.md

View file

@ -242,6 +242,8 @@ MD050:
MD051:
# Ignore case of fragments
ignore_case: false
# Pattern for ignoring additional fragments
ignored_pattern: ""
# MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md052.md
MD052:

View file

@ -483,6 +483,11 @@ for (const rule of rules) {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
}
};
break;

View file

@ -1511,6 +1511,11 @@
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
}
},
"additionalProperties": false
@ -1527,6 +1532,11 @@
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
}
},
"additionalProperties": false

View file

@ -1511,6 +1511,11 @@
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
}
},
"additionalProperties": false
@ -1527,6 +1532,11 @@
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
}
},
"additionalProperties": false

View file

@ -0,0 +1,9 @@
# Link Fragments Ignored Pattern Default
## Heading
[Present](#heading)
[Ignored](#ignored) {MD051}
[Missing](#missing) {MD051}

View file

@ -0,0 +1,15 @@
# Link Fragments Ignored Pattern Empty
## Heading
[Present](#heading)
[Ignored](#ignored) {MD051}
[Missing](#missing) {MD051}
<!-- markdownlint-configure-file {
"link-fragments": {
"ignored_pattern": ""
}
} -->

View file

@ -0,0 +1,15 @@
# Link Fragments Ignored Pattern Multiple
## Heading
[Present](#heading)
[Ignored](#ignored)
[Missing](#missing)
<!-- markdownlint-configure-file {
"link-fragments": {
"ignored_pattern": "^igno|^missing$"
}
} -->

View file

@ -0,0 +1,15 @@
# Link Fragments Ignored Pattern Present
## Heading
[Present](#heading)
[Ignored](#ignored)
[Missing](#missing) {MD051}
<!-- markdownlint-configure-file {
"link-fragments": {
"ignored_pattern": "^igno"
}
} -->

View file

@ -907,7 +907,7 @@ test("readme", async(t) => {
});
test("validateJsonUsingConfigSchemaStrict", async(t) => {
t.plan(196);
t.plan(199);
// @ts-ignore
const ajv = new Ajv(ajvOptions);
const validateSchemaStrict = ajv.compile(configSchemaStrict);

View file

@ -25399,6 +25399,179 @@ Generated by [AVA](https://avajs.dev).
`,
}
## link-fragments-ignored-pattern-default.md
> Snapshot 1
{
errors: [
{
errorContext: '[Ignored](#ignored)',
errorDetail: null,
errorRange: [
1,
19,
],
fixInfo: null,
lineNumber: 7,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
{
errorContext: '[Missing](#missing)',
errorDetail: null,
errorRange: [
1,
19,
],
fixInfo: null,
lineNumber: 9,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
],
fixed: `# Link Fragments Ignored Pattern Default␊
## Heading␊
[Present](#heading)␊
[Ignored](#ignored) {MD051}␊
[Missing](#missing) {MD051}␊
`,
}
## link-fragments-ignored-pattern-empty.md
> Snapshot 1
{
errors: [
{
errorContext: '[Ignored](#ignored)',
errorDetail: null,
errorRange: [
1,
19,
],
fixInfo: null,
lineNumber: 7,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
{
errorContext: '[Missing](#missing)',
errorDetail: null,
errorRange: [
1,
19,
],
fixInfo: null,
lineNumber: 9,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
],
fixed: `# Link Fragments Ignored Pattern Empty␊
## Heading␊
[Present](#heading)␊
[Ignored](#ignored) {MD051}␊
[Missing](#missing) {MD051}␊
<!-- markdownlint-configure-file {␊
"link-fragments": {␊
"ignored_pattern": ""␊
}␊
} -->␊
`,
}
## link-fragments-ignored-pattern-multiple.md
> Snapshot 1
{
errors: [],
fixed: `# Link Fragments Ignored Pattern Multiple␊
## Heading␊
[Present](#heading)␊
[Ignored](#ignored)␊
[Missing](#missing)␊
<!-- markdownlint-configure-file {␊
"link-fragments": {␊
"ignored_pattern": "^igno|^missing$"␊
}␊
} -->␊
`,
}
## link-fragments-ignored-pattern-present.md
> Snapshot 1
{
errors: [
{
errorContext: '[Missing](#missing)',
errorDetail: null,
errorRange: [
1,
19,
],
fixInfo: null,
lineNumber: 9,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
],
fixed: `# Link Fragments Ignored Pattern Present␊
## Heading␊
[Present](#heading)␊
[Ignored](#ignored)␊
[Missing](#missing) {MD051}␊
<!-- markdownlint-configure-file {␊
"link-fragments": {␊
"ignored_pattern": "^igno"␊
}␊
} -->␊
`,
}
## link-fragments.md
> Snapshot 1