Update MD051/link-fragments to add ignore_case parameter and improve documentation (fixes #1274).

This commit is contained in:
David Anson 2024-10-08 22:40:11 -07:00
parent 74aa96d19d
commit 04c693b00b
16 changed files with 315 additions and 44 deletions

View file

@ -6245,7 +6245,7 @@ module.exports = [
const { addError, addErrorDetailIf, getHtmlAttributeRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"); const { addError, getHtmlAttributeRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
const { filterByPredicate, filterByTypes, getHtmlTagInfo } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs"); const { filterByPredicate, filterByTypes, getHtmlTagInfo } = __webpack_require__(/*! ../helpers/micromark-helpers.cjs */ "../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js"); const { filterByTypesCached } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
@ -6311,6 +6311,7 @@ module.exports = {
"tags": [ "links" ], "tags": [ "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD051(params, onError) { "function": function MD051(params, onError) {
const ignoreCase = params.config.ignore_case || false;
const fragments = new Map(); const fragments = new Map();
// Process headings // Process headings
@ -6386,16 +6387,16 @@ module.exports = {
if (mixedCaseKey) { if (mixedCaseKey) {
// @ts-ignore // @ts-ignore
(fixInfo || {}).insertText = mixedCaseKey; (fixInfo || {}).insertText = mixedCaseKey;
addErrorDetailIf( if (!ignoreCase && (mixedCaseKey !== text)) {
onError, addError(
link.startLine, onError,
mixedCaseKey, link.startLine,
text, `Expected: ${mixedCaseKey}; Actual: ${text}`,
undefined, context,
context, range,
range, fixInfo
fixInfo );
); }
} else { } else {
addError( addError(
onError, onError,

View file

@ -16,9 +16,9 @@ generated name (see below):
[Link](#heading-name) [Link](#heading-name)
``` ```
Link fragments may be handled case-sensitively, so this rule requires fragments For consistency, this rule requires fragments to exactly match the [GitHub
to exactly match the [GitHub heading algorithm][github-heading-algorithm]. heading algorithm][github-heading-algorithm] which converts letters to
Therefore, the following example is reported as a violation: lowercase. Therefore, the following example is reported as a violation:
```markdown ```markdown
# Heading Name # Heading Name
@ -26,6 +26,10 @@ Therefore, the following example is reported as a violation:
[Link](#Heading-Name) [Link](#Heading-Name)
``` ```
To ignore case when comparing fragments with heading names, the `ignore_case`
parameter can be set to `true`. In this configuration, the previous example is
not reported as a violation.
Alternatively, some platforms allow the syntax `{#named-anchor}` to be used Alternatively, some platforms allow the syntax `{#named-anchor}` to be used
within a heading to provide a specific name (consisting of only lower-case within a heading to provide a specific name (consisting of only lower-case
letters, numbers, `-`, and `_`): letters, numbers, `-`, and `_`):

View file

@ -2100,6 +2100,10 @@ Tags: `links`
Aliases: `link-fragments` Aliases: `link-fragments`
Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`)
Fixable: Some violations can be fixed by tooling Fixable: Some violations can be fixed by tooling
This rule is triggered when a link fragment does not match any of the fragments This rule is triggered when a link fragment does not match any of the fragments
@ -2120,9 +2124,9 @@ generated name (see below):
[Link](#heading-name) [Link](#heading-name)
``` ```
Link fragments may be handled case-sensitively, so this rule requires fragments For consistency, this rule requires fragments to exactly match the [GitHub
to exactly match the [GitHub heading algorithm][github-heading-algorithm]. heading algorithm][github-heading-algorithm] which converts letters to
Therefore, the following example is reported as a violation: lowercase. Therefore, the following example is reported as a violation:
```markdown ```markdown
# Heading Name # Heading Name
@ -2130,6 +2134,10 @@ Therefore, the following example is reported as a violation:
[Link](#Heading-Name) [Link](#Heading-Name)
``` ```
To ignore case when comparing fragments with heading names, the `ignore_case`
parameter can be set to `true`. In this configuration, the previous example is
not reported as a violation.
Alternatively, some platforms allow the syntax `{#named-anchor}` to be used Alternatively, some platforms allow the syntax `{#named-anchor}` to be used
within a heading to provide a specific name (consisting of only lower-case within a heading to provide a specific name (consisting of only lower-case
letters, numbers, `-`, and `_`): letters, numbers, `-`, and `_`):

View file

@ -4,6 +4,10 @@ Tags: `links`
Aliases: `link-fragments` Aliases: `link-fragments`
Parameters:
- `ignore_case`: Ignore case of fragments (`boolean`, default `false`)
Fixable: Some violations can be fixed by tooling Fixable: Some violations can be fixed by tooling
This rule is triggered when a link fragment does not match any of the fragments This rule is triggered when a link fragment does not match any of the fragments
@ -24,9 +28,9 @@ generated name (see below):
[Link](#heading-name) [Link](#heading-name)
``` ```
Link fragments may be handled case-sensitively, so this rule requires fragments For consistency, this rule requires fragments to exactly match the [GitHub
to exactly match the [GitHub heading algorithm][github-heading-algorithm]. heading algorithm][github-heading-algorithm] which converts letters to
Therefore, the following example is reported as a violation: lowercase. Therefore, the following example is reported as a violation:
```markdown ```markdown
# Heading Name # Heading Name
@ -34,6 +38,10 @@ Therefore, the following example is reported as a violation:
[Link](#Heading-Name) [Link](#Heading-Name)
``` ```
To ignore case when comparing fragments with heading names, the `ignore_case`
parameter can be set to `true`. In this configuration, the previous example is
not reported as a violation.
Alternatively, some platforms allow the syntax `{#named-anchor}` to be used Alternatively, some platforms allow the syntax `{#named-anchor}` to be used
within a heading to provide a specific name (consisting of only lower-case within a heading to provide a specific name (consisting of only lower-case
letters, numbers, `-`, and `_`): letters, numbers, `-`, and `_`):

View file

@ -937,11 +937,25 @@ export interface ConfigurationStrict {
/** /**
* MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md * MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md
*/ */
MD051?: boolean; MD051?:
| boolean
| {
/**
* Ignore case of fragments
*/
ignore_case?: boolean;
};
/** /**
* MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md * MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md
*/ */
"link-fragments"?: boolean; "link-fragments"?:
| boolean
| {
/**
* Ignore case of fragments
*/
ignore_case?: boolean;
};
/** /**
* MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/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.35.0/doc/md052.md
*/ */

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
const { addError, addErrorDetailIf, getHtmlAttributeRe } = require("../helpers"); const { addError, getHtmlAttributeRe } = require("../helpers");
const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark-helpers.cjs"); const { filterByPredicate, filterByTypes, getHtmlTagInfo } = require("../helpers/micromark-helpers.cjs");
const { filterByTypesCached } = require("./cache"); const { filterByTypesCached } = require("./cache");
@ -68,6 +68,7 @@ module.exports = {
"tags": [ "links" ], "tags": [ "links" ],
"parser": "micromark", "parser": "micromark",
"function": function MD051(params, onError) { "function": function MD051(params, onError) {
const ignoreCase = params.config.ignore_case || false;
const fragments = new Map(); const fragments = new Map();
// Process headings // Process headings
@ -143,16 +144,16 @@ module.exports = {
if (mixedCaseKey) { if (mixedCaseKey) {
// @ts-ignore // @ts-ignore
(fixInfo || {}).insertText = mixedCaseKey; (fixInfo || {}).insertText = mixedCaseKey;
addErrorDetailIf( if (!ignoreCase && (mixedCaseKey !== text)) {
onError, addError(
link.startLine, onError,
mixedCaseKey, link.startLine,
text, `Expected: ${mixedCaseKey}; Actual: ${text}`,
undefined, context,
context, range,
range, fixInfo
fixInfo );
); }
} else { } else {
addError( addError(
onError, onError,

View file

@ -261,7 +261,10 @@
}, },
// MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md // MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md
"MD051": true, "MD051": {
// Ignore case of fragments
"ignore_case": false
},
// MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/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.35.0/doc/md052.md
"MD052": { "MD052": {

View file

@ -235,7 +235,9 @@ MD050:
style: "consistent" style: "consistent"
# MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md # MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md
MD051: true MD051:
# Ignore case of fragments
ignore_case: false
# MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/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.35.0/doc/md052.md
MD052: MD052:

View file

@ -477,6 +477,15 @@ for (const rule of rules) {
} }
}; };
break; break;
case "MD051":
scheme.properties = {
"ignore_case": {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
}
};
break;
case "MD052": case "MD052":
scheme.properties = { scheme.properties = {
"shortcut_syntax": { "shortcut_syntax": {

View file

@ -1464,13 +1464,35 @@
}, },
"MD051": { "MD051": {
"description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md", "description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md",
"type": "boolean", "type": [
"default": true "boolean",
"object"
],
"default": true,
"properties": {
"ignore_case": {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}, },
"link-fragments": { "link-fragments": {
"description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md", "description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md",
"type": "boolean", "type": [
"default": true "boolean",
"object"
],
"default": true,
"properties": {
"ignore_case": {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}, },
"MD052": { "MD052": {
"description": "MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md052.md", "description": "MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md052.md",

View file

@ -1464,13 +1464,35 @@
}, },
"MD051": { "MD051": {
"description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md", "description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md",
"type": "boolean", "type": [
"default": true "boolean",
"object"
],
"default": true,
"properties": {
"ignore_case": {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}, },
"link-fragments": { "link-fragments": {
"description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md", "description": "MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md051.md",
"type": "boolean", "type": [
"default": true "boolean",
"object"
],
"default": true,
"properties": {
"ignore_case": {
"description": "Ignore case of fragments",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}, },
"MD052": { "MD052": {
"description": "MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md052.md", "description": "MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/md052.md",

View file

@ -0,0 +1,23 @@
# Link Fragments Default Case
## Heading Name
[Valid](#heading-name)
[Invalid](#Heading-Name) {MD051}
## Valid *Heading* With _Emphasis_
[Valid](#valid-heading-with-emphasis)
[Invalid](#Valid-Heading-With-Emphasis) {MD051}
## 🚀 Valid Heading With Emoji
[Valid](#-valid-heading-with-emoji)
[Invalid](#-Valid-Heading-With-Emoji) {MD051}
<!-- markdownlint-configure-file {
"emphasis-style": false
} -->

View file

@ -0,0 +1,26 @@
# Link Fragments Ignore Case
## Heading Name
[Valid](#heading-name)
[Valid](#Heading-Name)
## Valid *Heading* With _Emphasis_
[Valid](#valid-heading-with-emphasis)
[Valid](#Valid-Heading-With-Emphasis)
## 🚀 Valid Heading With Emoji
[Valid](#-valid-heading-with-emoji)
[Valid](#-Valid-Heading-With-Emoji)
<!-- markdownlint-configure-file {
"emphasis-style": false,
"link-fragments": {
"ignore_case": true
}
} -->

View file

@ -941,7 +941,7 @@ test("readme", async(t) => {
}); });
test("validateJsonUsingConfigSchemaStrict", async(t) => { test("validateJsonUsingConfigSchemaStrict", async(t) => {
t.plan(179); t.plan(181);
// @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

@ -24546,6 +24546,134 @@ Generated by [AVA](https://avajs.dev).
`, `,
} }
## link-fragments-default-case.md
> Snapshot 1
{
errors: [
{
errorContext: '[Invalid](#Heading-Name)',
errorDetail: 'Expected: #heading-name; Actual: #Heading-Name',
errorRange: [
1,
24,
],
fixInfo: {
deleteCount: 13,
editColumn: 11,
insertText: '#heading-name',
},
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: '[Invalid](#Valid-Heading-With-Emphasis)',
errorDetail: 'Expected: #valid-heading-with-emphasis; Actual: #Valid-Heading-With-Emphasis',
errorRange: [
1,
39,
],
fixInfo: {
deleteCount: 28,
editColumn: 11,
insertText: '#valid-heading-with-emphasis',
},
lineNumber: 13,
ruleDescription: 'Link fragments should be valid',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md051.md',
ruleNames: [
'MD051',
'link-fragments',
],
},
{
errorContext: '[Invalid](#-Valid-Heading-With-Emoji)',
errorDetail: 'Expected: #-valid-heading-with-emoji; Actual: #-Valid-Heading-With-Emoji',
errorRange: [
1,
37,
],
fixInfo: {
deleteCount: 26,
editColumn: 11,
insertText: '#-valid-heading-with-emoji',
},
lineNumber: 19,
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 Default Case␊
## Heading Name␊
[Valid](#heading-name)␊
[Invalid](#heading-name) {MD051}␊
## Valid *Heading* With _Emphasis_
[Valid](#valid-heading-with-emphasis)␊
[Invalid](#valid-heading-with-emphasis) {MD051}␊
## 🚀 Valid Heading With Emoji␊
[Valid](#-valid-heading-with-emoji)␊
[Invalid](#-valid-heading-with-emoji) {MD051}␊
<!-- markdownlint-configure-file {␊
"emphasis-style": false␊
} -->␊
`,
}
## link-fragments-ignore-case.md
> Snapshot 1
{
errors: [],
fixed: `# Link Fragments Ignore Case␊
## Heading Name␊
[Valid](#heading-name)␊
[Valid](#Heading-Name)␊
## Valid *Heading* With _Emphasis_
[Valid](#valid-heading-with-emphasis)␊
[Valid](#Valid-Heading-With-Emphasis)␊
## 🚀 Valid Heading With Emoji␊
[Valid](#-valid-heading-with-emoji)␊
[Valid](#-Valid-Heading-With-Emoji)␊
<!-- markdownlint-configure-file {␊
"emphasis-style": false,␊
"link-fragments": {␊
"ignore_case": true␊
}␊
} -->␊
`,
}
## link-fragments.md ## link-fragments.md
> Snapshot 1 > Snapshot 1