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) [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 Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub. automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document. 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-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 [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 [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: Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`) - `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 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) [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 Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub. automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document. 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-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 [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 [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> <a name="md052"></a>

View file

@ -7,6 +7,8 @@ Aliases: `link-fragments`
Parameters: Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`) - `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 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) [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 Rationale: [GitHub section links][github-section-links] are created
automatically for every heading when Markdown content is displayed on GitHub. automatically for every heading when Markdown content is displayed on GitHub.
This makes it easy to link directly to different sections within a document. 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-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 [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 [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 of fragments
*/ */
ignore_case?: boolean; 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 * 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 of fragments
*/ */
ignore_case?: boolean; 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 * 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", "parser": "micromark",
"function": function MD051(params, onError) { "function": function MD051(params, onError) {
const ignoreCase = params.config.ignore_case || false; const ignoreCase = params.config.ignore_case || false;
const ignoredPattern = params.config.ignored_pattern || "";
const ignoredPatternRe = new RegExp(ignoredPattern || "^$");
/** @type {Map<string, number>} */ /** @type {Map<string, number>} */
const fragments = new Map([ [ "#top", 0 ] ]); const fragments = new Map([ [ "#top", 0 ] ]);
@ -114,12 +116,14 @@ export default {
for (const definition of definitions) { for (const definition of definitions) {
const { endColumn, startColumn } = definition; const { endColumn, startColumn } = definition;
const text = unescapeStringTokenText(definition); const text = unescapeStringTokenText(definition);
const encodedText = `#${encodeURIComponent(text.slice(1))}`; const textSliceOne = text.slice(1);
const encodedText = `#${encodeURIComponent(textSliceOne)}`;
if ( if (
(text.length > 1) && (text.length > 1) &&
text.startsWith("#") && text.startsWith("#") &&
!fragments.has(encodedText) && !fragments.has(encodedText) &&
!lineFragmentRe.test(encodedText) !lineFragmentRe.test(encodedText) &&
!ignoredPatternRe.test(textSliceOne)
) { ) {
let context = undefined; let context = undefined;
let range = 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/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md051.md
"MD051": { "MD051": {
// Ignore case of fragments // 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 // 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: MD051:
# Ignore case of fragments # 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 # 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: MD052:

View file

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

View file

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

View file

@ -1511,6 +1511,11 @@
"description": "Ignore case of fragments", "description": "Ignore case of fragments",
"type": "boolean", "type": "boolean",
"default": false "default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
} }
}, },
"additionalProperties": false "additionalProperties": false
@ -1527,6 +1532,11 @@
"description": "Ignore case of fragments", "description": "Ignore case of fragments",
"type": "boolean", "type": "boolean",
"default": false "default": false
},
"ignored_pattern": {
"description": "Pattern for ignoring additional fragments",
"type": "string",
"default": ""
} }
}, },
"additionalProperties": false "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) => { test("validateJsonUsingConfigSchemaStrict", async(t) => {
t.plan(196); t.plan(199);
// @ts-ignore // @ts-ignore
const ajv = new Ajv(ajvOptions); const ajv = new Ajv(ajvOptions);
const validateSchemaStrict = ajv.compile(configSchemaStrict); 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 ## link-fragments.md
> Snapshot 1 > Snapshot 1