mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 14:00:13 +01: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
|
* **[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
|
* **[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
|
* **[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
|
* **[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
|
* **[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
|
* **[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
|
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
|
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
|
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
|
Note: The `level` parameter can be used to change the top level (ex: to h2) in
|
||||||
cases where an h1 is added externally.
|
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>
|
<a name="md026"></a>
|
||||||
|
|
||||||
## MD026 - Trailing punctuation in heading
|
## MD026 - Trailing punctuation in heading
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,21 @@
|
||||||
const shared = require("./shared");
|
const shared = require("./shared");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"names": [ "MD025", "single-h1" ],
|
"names": [ "MD025", "single-title", "single-h1" ],
|
||||||
"description": "Multiple top level headings in the same document",
|
"description": "Multiple top level headings in the same document",
|
||||||
"tags": [ "headings", "headers" ],
|
"tags": [ "headings", "headers" ],
|
||||||
"function": function MD025(params, onError) {
|
"function": function MD025(params, onError) {
|
||||||
const level = params.config.level || 1;
|
const level = params.config.level || 1;
|
||||||
const tag = "h" + level;
|
const tag = "h" + level;
|
||||||
|
const foundFrontMatterTitle =
|
||||||
|
shared.frontMatterHasTitle(
|
||||||
|
params.frontMatterLines,
|
||||||
|
params.config.front_matter_title
|
||||||
|
);
|
||||||
let hasTopLevelHeading = false;
|
let hasTopLevelHeading = false;
|
||||||
shared.filterTokens(params, "heading_open", function forToken(token) {
|
shared.filterTokens(params, "heading_open", function forToken(token) {
|
||||||
if (token.tag === tag) {
|
if (token.tag === tag) {
|
||||||
if (hasTopLevelHeading) {
|
if (hasTopLevelHeading || foundFrontMatterTitle) {
|
||||||
shared.addErrorContext(onError, token.lineNumber,
|
shared.addErrorContext(onError, token.lineNumber,
|
||||||
token.line.trim());
|
token.line.trim());
|
||||||
} else if (token.lineNumber === 1) {
|
} else if (token.lineNumber === 1) {
|
||||||
|
|
|
||||||
12
lib/md041.js
12
lib/md041.js
|
|
@ -11,13 +11,11 @@ module.exports = {
|
||||||
"function": function MD041(params, onError) {
|
"function": function MD041(params, onError) {
|
||||||
const level = params.config.level || 1;
|
const level = params.config.level || 1;
|
||||||
const tag = "h" + level;
|
const tag = "h" + level;
|
||||||
const frontMatterTitle = params.config.front_matter_title;
|
const foundFrontMatterTitle =
|
||||||
const ignoreFrontMatter =
|
shared.frontMatterHasTitle(
|
||||||
(frontMatterTitle !== undefined) && !frontMatterTitle;
|
params.frontMatterLines,
|
||||||
const frontMatterTitleRe =
|
params.config.front_matter_title
|
||||||
new RegExp(frontMatterTitle || "^\\s*title\\s*[:=]", "i");
|
);
|
||||||
const foundFrontMatterTitle = !ignoreFrontMatter &&
|
|
||||||
params.frontMatterLines.some((line) => frontMatterTitleRe.test(line));
|
|
||||||
if (!foundFrontMatterTitle) {
|
if (!foundFrontMatterTitle) {
|
||||||
params.tokens.every((token) => {
|
params.tokens.every((token) => {
|
||||||
if (token.type === "html_block") {
|
if (token.type === "html_block") {
|
||||||
|
|
|
||||||
|
|
@ -334,18 +334,18 @@ module.exports.addErrorDetailIf = function addErrorDetailIf(
|
||||||
|
|
||||||
// Adds an error object with context via the onError callback
|
// Adds an error object with context via the onError callback
|
||||||
module.exports.addErrorContext =
|
module.exports.addErrorContext =
|
||||||
function addErrorContext(onError, lineNumber, context, left, right, range) {
|
function addErrorContext(onError, lineNumber, context, left, right, range) {
|
||||||
if (context.length <= 30) {
|
if (context.length <= 30) {
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
} else if (left && right) {
|
} else if (left && right) {
|
||||||
context = context.substr(0, 15) + "..." + context.substr(-15);
|
context = context.substr(0, 15) + "..." + context.substr(-15);
|
||||||
} else if (right) {
|
} else if (right) {
|
||||||
context = "..." + context.substr(-30);
|
context = "..." + context.substr(-30);
|
||||||
} else {
|
} else {
|
||||||
context = context.substr(0, 30) + "...";
|
context = context.substr(0, 30) + "...";
|
||||||
}
|
}
|
||||||
addError(onError, lineNumber, null, context, range);
|
addError(onError, lineNumber, null, context, range);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a range object for a line by applying a RegExp
|
// Returns a range object for a line by applying a RegExp
|
||||||
module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
||||||
|
|
@ -362,3 +362,14 @@ module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) {
|
||||||
}
|
}
|
||||||
return range;
|
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;
|
let custom = true;
|
||||||
switch (rule.names[0]) {
|
switch (rule.names[0]) {
|
||||||
case "MD002":
|
case "MD002":
|
||||||
case "MD025":
|
|
||||||
scheme.properties = {
|
scheme.properties = {
|
||||||
"level": {
|
"level": {
|
||||||
"description": "Heading level",
|
"description": "Heading level",
|
||||||
|
|
@ -236,6 +235,7 @@ rules.forEach(function forRule(rule) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
case "MD025":
|
||||||
case "MD041":
|
case "MD041":
|
||||||
scheme.properties = {
|
scheme.properties = {
|
||||||
"level": {
|
"level": {
|
||||||
|
|
|
||||||
|
|
@ -577,7 +577,7 @@
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"MD025": {
|
"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": [
|
"type": [
|
||||||
"boolean",
|
"boolean",
|
||||||
"object"
|
"object"
|
||||||
|
|
@ -588,12 +588,38 @@
|
||||||
"description": "Heading level",
|
"description": "Heading level",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 1
|
"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
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"single-h1": {
|
"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": [
|
"type": [
|
||||||
"boolean",
|
"boolean",
|
||||||
"object"
|
"object"
|
||||||
|
|
@ -604,6 +630,11 @@
|
||||||
"description": "Heading level",
|
"description": "Heading level",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"default": 1
|
"default": 1
|
||||||
|
},
|
||||||
|
"front_matter_title": {
|
||||||
|
"description": "RegExp for matching title in front matter",
|
||||||
|
"type": "string",
|
||||||
|
"default": "^\\s*title\\s*[:=]"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
|
@ -955,7 +986,28 @@
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
"MD041": {
|
"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": [
|
"type": [
|
||||||
"boolean",
|
"boolean",
|
||||||
"object"
|
"object"
|
||||||
|
|
@ -976,7 +1028,7 @@
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"first-line-h1": {
|
"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": [
|
"type": [
|
||||||
"boolean",
|
"boolean",
|
||||||
"object"
|
"object"
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lineNumber": 4,
|
"lineNumber": 4,
|
||||||
"ruleNames": [ "MD025", "single-h1" ],
|
"ruleNames": [ "MD025", "single-title", "single-h1" ],
|
||||||
"ruleDescription": "Multiple top level headings in the same document",
|
"ruleDescription": "Multiple top level headings in the same document",
|
||||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md025",
|
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md025",
|
||||||
"errorDetail": null,
|
"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
|
date: 2015-11-17 16:16:01 -0600
|
||||||
categories: jekyll update
|
categories: jekyll update
|
||||||
---
|
---
|
||||||
# Top level heading
|
# Top level heading {MD025}
|
||||||
|
|
||||||
Front matter from [Jekyll documentation](https://jekyllrb.com/docs/posts/#a-typical-post).
|
Front matter from [Jekyll documentation](https://jekyllrb.com/docs/posts/#a-typical-post).
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
"default": true,
|
"default": true,
|
||||||
|
"MD025": {
|
||||||
|
"front_matter_title": ""
|
||||||
|
},
|
||||||
"MD041": true
|
"MD041": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
{
|
{
|
||||||
"default": true,
|
"default": true,
|
||||||
|
"MD025": {
|
||||||
|
"front_matter_title": ""
|
||||||
|
},
|
||||||
"MD041": true
|
"MD041": true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ tags:
|
||||||
url: https://example.com
|
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.
|
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.
|
This is just a sample post.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue