mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Add front_matter_title parameter to MD025/single-title/single-h1 (refs #169).
This commit is contained in:
parent
050cbbba82
commit
61d6311a3e
14 changed files with 124 additions and 32 deletions
|
@ -66,7 +66,7 @@ playground for learning and exploring.
|
|||
* **[MD022](doc/Rules.md#md022)** *blanks-around-headings/blanks-around-headers* - Headings should be surrounded by blank lines
|
||||
* **[MD023](doc/Rules.md#md023)** *heading-start-left/header-start-left* - Headings must start at the beginning of the line
|
||||
* **[MD024](doc/Rules.md#md024)** *no-duplicate-heading/no-duplicate-header* - Multiple headings with the same content
|
||||
* **[MD025](doc/Rules.md#md025)** *single-h1* - Multiple top level headings in the same document
|
||||
* **[MD025](doc/Rules.md#md025)** *single-title/single-h1* - Multiple top level headings in the same document
|
||||
* **[MD026](doc/Rules.md#md026)** *no-trailing-punctuation* - Trailing punctuation in heading
|
||||
* **[MD027](doc/Rules.md#md027)** *no-multiple-space-blockquote* - Multiple spaces after blockquote symbol
|
||||
* **[MD028](doc/Rules.md#md028)** *no-blanks-blockquote* - Blank line inside blockquote
|
||||
|
|
11
doc/Rules.md
11
doc/Rules.md
|
@ -730,9 +730,9 @@ in change logs):
|
|||
|
||||
Tags: headings, headers
|
||||
|
||||
Aliases: single-h1
|
||||
Aliases: single-title, single-h1
|
||||
|
||||
Parameters: level (number; default 1)
|
||||
Parameters: level, front_matter_title (number; default 1, string; default "^\s*title:")
|
||||
|
||||
This rule is triggered when a top level heading is in use (the first line of
|
||||
the file is an h1 heading), and more than one h1 heading is in use in the
|
||||
|
@ -764,6 +764,13 @@ should be contained within this heading.
|
|||
Note: The `level` parameter can be used to change the top level (ex: to h2) in
|
||||
cases where an h1 is added externally.
|
||||
|
||||
If [YAML](https://en.wikipedia.org/wiki/YAML) front matter is present and contains
|
||||
a `title` property (commonly used with blog posts), this rule treats that as a top
|
||||
level heading and will report a violation for any subsequent top level headings.
|
||||
To use a different property name in front matter, specify the text of a regular
|
||||
expression via the `front_matter_title` parameter. To disable the use of front
|
||||
matter by this rule, specify `""` for `front_matter_title`.
|
||||
|
||||
<a name="md026"></a>
|
||||
|
||||
## MD026 - Trailing punctuation in heading
|
||||
|
|
|
@ -5,16 +5,21 @@
|
|||
const shared = require("./shared");
|
||||
|
||||
module.exports = {
|
||||
"names": [ "MD025", "single-h1" ],
|
||||
"names": [ "MD025", "single-title", "single-h1" ],
|
||||
"description": "Multiple top level headings in the same document",
|
||||
"tags": [ "headings", "headers" ],
|
||||
"function": function MD025(params, onError) {
|
||||
const level = params.config.level || 1;
|
||||
const tag = "h" + level;
|
||||
const foundFrontMatterTitle =
|
||||
shared.frontMatterHasTitle(
|
||||
params.frontMatterLines,
|
||||
params.config.front_matter_title
|
||||
);
|
||||
let hasTopLevelHeading = false;
|
||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
||||
if (token.tag === tag) {
|
||||
if (hasTopLevelHeading) {
|
||||
if (hasTopLevelHeading || foundFrontMatterTitle) {
|
||||
shared.addErrorContext(onError, token.lineNumber,
|
||||
token.line.trim());
|
||||
} else if (token.lineNumber === 1) {
|
||||
|
|
12
lib/md041.js
12
lib/md041.js
|
@ -11,13 +11,11 @@ module.exports = {
|
|||
"function": function MD041(params, onError) {
|
||||
const level = params.config.level || 1;
|
||||
const tag = "h" + level;
|
||||
const frontMatterTitle = params.config.front_matter_title;
|
||||
const ignoreFrontMatter =
|
||||
(frontMatterTitle !== undefined) && !frontMatterTitle;
|
||||
const frontMatterTitleRe =
|
||||
new RegExp(frontMatterTitle || "^\\s*title\\s*[:=]", "i");
|
||||
const foundFrontMatterTitle = !ignoreFrontMatter &&
|
||||
params.frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
||||
const foundFrontMatterTitle =
|
||||
shared.frontMatterHasTitle(
|
||||
params.frontMatterLines,
|
||||
params.config.front_matter_title
|
||||
);
|
||||
if (!foundFrontMatterTitle) {
|
||||
params.tokens.every((token) => {
|
||||
if (token.type === "html_block") {
|
||||
|
|
|
@ -334,18 +334,18 @@ module.exports.addErrorDetailIf = function addErrorDetailIf(
|
|||
|
||||
// Adds an error object with context via the onError callback
|
||||
module.exports.addErrorContext =
|
||||
function addErrorContext(onError, lineNumber, context, left, right, range) {
|
||||
if (context.length <= 30) {
|
||||
// Nothing to do
|
||||
} else if (left && right) {
|
||||
context = context.substr(0, 15) + "..." + context.substr(-15);
|
||||
} else if (right) {
|
||||
context = "..." + context.substr(-30);
|
||||
} else {
|
||||
context = context.substr(0, 30) + "...";
|
||||
}
|
||||
addError(onError, lineNumber, null, context, range);
|
||||
};
|
||||
function addErrorContext(onError, lineNumber, context, left, right, range) {
|
||||
if (context.length <= 30) {
|
||||
// Nothing to do
|
||||
} else if (left && right) {
|
||||
context = context.substr(0, 15) + "..." + context.substr(-15);
|
||||
} else if (right) {
|
||||
context = "..." + context.substr(-30);
|
||||
} else {
|
||||
context = context.substr(0, 30) + "...";
|
||||
}
|
||||
addError(onError, lineNumber, null, context, range);
|
||||
};
|
||||
|
||||
// Returns a range object for a line by applying a RegExp
|
||||
module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
||||
|
@ -362,3 +362,14 @@ module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
|||
}
|
||||
return range;
|
||||
};
|
||||
|
||||
// Determines if the front matter includes a title
|
||||
module.exports.frontMatterHasTitle =
|
||||
function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) {
|
||||
const ignoreFrontMatter =
|
||||
(frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern;
|
||||
const frontMatterTitleRe =
|
||||
new RegExp(frontMatterTitlePattern || "^\\s*title\\s*[:=]", "i");
|
||||
return !ignoreFrontMatter &&
|
||||
frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
||||
};
|
||||
|
|
|
@ -40,7 +40,6 @@ rules.forEach(function forRule(rule) {
|
|||
let custom = true;
|
||||
switch (rule.names[0]) {
|
||||
case "MD002":
|
||||
case "MD025":
|
||||
scheme.properties = {
|
||||
"level": {
|
||||
"description": "Heading level",
|
||||
|
@ -236,6 +235,7 @@ rules.forEach(function forRule(rule) {
|
|||
}
|
||||
};
|
||||
break;
|
||||
case "MD025":
|
||||
case "MD041":
|
||||
scheme.properties = {
|
||||
"level": {
|
||||
|
|
|
@ -577,7 +577,7 @@
|
|||
"additionalProperties": false
|
||||
},
|
||||
"MD025": {
|
||||
"description": "MD025/single-h1 - Multiple top level headings in the same document",
|
||||
"description": "MD025/single-title/single-h1 - Multiple top level headings in the same document",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
|
@ -588,12 +588,38 @@
|
|||
"description": "Heading level",
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
},
|
||||
"front_matter_title": {
|
||||
"description": "RegExp for matching title in front matter",
|
||||
"type": "string",
|
||||
"default": "^\\s*title\\s*[:=]"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"single-title": {
|
||||
"description": "MD025/single-title/single-h1 - Multiple top level headings in the same document",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
],
|
||||
"default": true,
|
||||
"properties": {
|
||||
"level": {
|
||||
"description": "Heading level",
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
},
|
||||
"front_matter_title": {
|
||||
"description": "RegExp for matching title in front matter",
|
||||
"type": "string",
|
||||
"default": "^\\s*title\\s*[:=]"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"single-h1": {
|
||||
"description": "MD025/single-h1 - Multiple top level headings in the same document",
|
||||
"description": "MD025/single-title/single-h1 - Multiple top level headings in the same document",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
|
@ -604,6 +630,11 @@
|
|||
"description": "Heading level",
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
},
|
||||
"front_matter_title": {
|
||||
"description": "RegExp for matching title in front matter",
|
||||
"type": "string",
|
||||
"default": "^\\s*title\\s*[:=]"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
@ -955,7 +986,28 @@
|
|||
"default": true
|
||||
},
|
||||
"MD041": {
|
||||
"description": "MD041/first-line-h1 - First line in file should be a top level heading",
|
||||
"description": "MD041/first-line-heading/first-line-h1 - First line in file should be a top level heading",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
],
|
||||
"default": true,
|
||||
"properties": {
|
||||
"level": {
|
||||
"description": "Heading level",
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
},
|
||||
"front_matter_title": {
|
||||
"description": "RegExp for matching title in front matter",
|
||||
"type": "string",
|
||||
"default": "^\\s*title\\s*[:=]"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"first-line-heading": {
|
||||
"description": "MD041/first-line-heading/first-line-h1 - First line in file should be a top level heading",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
|
@ -976,7 +1028,7 @@
|
|||
"additionalProperties": false
|
||||
},
|
||||
"first-line-h1": {
|
||||
"description": "MD041/first-line-h1 - First line in file should be a top level heading",
|
||||
"description": "MD041/first-line-heading/first-line-h1 - First line in file should be a top level heading",
|
||||
"type": [
|
||||
"boolean",
|
||||
"object"
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
},
|
||||
{
|
||||
"lineNumber": 4,
|
||||
"ruleNames": [ "MD025", "single-h1" ],
|
||||
"ruleNames": [ "MD025", "single-title", "single-h1" ],
|
||||
"ruleDescription": "Multiple top level headings in the same document",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md025",
|
||||
"errorDetail": null,
|
||||
|
|
7
test/front-matter-alt-title-h1.json
Normal file
7
test/front-matter-alt-title-h1.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"default": true,
|
||||
"MD013": false,
|
||||
"MD025": {
|
||||
"front_matter_title": "^\\s*alternate="
|
||||
}
|
||||
}
|
6
test/front-matter-alt-title-h1.md
Normal file
6
test/front-matter-alt-title-h1.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
alternate="Welcome to Jekyll!"
|
||||
---
|
||||
# Top level heading {MD025}
|
||||
|
||||
Front matter from [Jekyll documentation](https://jekyllrb.com/docs/posts/#a-typical-post).
|
|
@ -4,6 +4,6 @@ title: "Welcome to Jekyll!"
|
|||
date: 2015-11-17 16:16:01 -0600
|
||||
categories: jekyll update
|
||||
---
|
||||
# Top level heading
|
||||
# Top level heading {MD025}
|
||||
|
||||
Front matter from [Jekyll documentation](https://jekyllrb.com/docs/posts/#a-typical-post).
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"default": true,
|
||||
"MD025": {
|
||||
"front_matter_title": ""
|
||||
},
|
||||
"MD041": true
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"default": true,
|
||||
"MD025": {
|
||||
"front_matter_title": ""
|
||||
},
|
||||
"MD041": true
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ tags:
|
|||
url: https://example.com
|
||||
excerpt: Hello World! Vestibulum imperdiet adipiscing arcu, quis aliquam dolor condimentum dapibus. Aliquam fermentum leo aliquet quam volutpat et molestie mauris mattis. Suspendisse semper consequat velit in suscipit.
|
||||
---
|
||||
# heading1
|
||||
# heading1 {MD025}
|
||||
|
||||
This is just a sample post.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue