mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 14:00:13 +01:00
Update MD041/first-line-heading to add an allow_preamble parameter (fixes #1416).
This commit is contained in:
parent
c061888937
commit
62dc79864d
17 changed files with 538 additions and 163 deletions
48
lib/configuration-strict.d.ts
vendored
48
lib/configuration-strict.d.ts
vendored
|
|
@ -406,14 +406,14 @@ export interface ConfigurationStrict {
|
|||
MD025?:
|
||||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md025.md
|
||||
|
|
@ -421,14 +421,14 @@ export interface ConfigurationStrict {
|
|||
"single-title"?:
|
||||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md025.md
|
||||
|
|
@ -436,14 +436,14 @@ export interface ConfigurationStrict {
|
|||
"single-h1"?:
|
||||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md026.md
|
||||
|
|
@ -730,13 +730,17 @@ export interface ConfigurationStrict {
|
|||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
* Allow content before first heading
|
||||
*/
|
||||
level?: number;
|
||||
allow_preamble?: boolean;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md041.md
|
||||
|
|
@ -745,13 +749,17 @@ export interface ConfigurationStrict {
|
|||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
* Allow content before first heading
|
||||
*/
|
||||
level?: number;
|
||||
allow_preamble?: boolean;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md041.md
|
||||
|
|
@ -760,13 +768,17 @@ export interface ConfigurationStrict {
|
|||
| boolean
|
||||
| {
|
||||
/**
|
||||
* Heading level
|
||||
* Allow content before first heading
|
||||
*/
|
||||
level?: number;
|
||||
allow_preamble?: boolean;
|
||||
/**
|
||||
* RegExp for matching title in front matter
|
||||
*/
|
||||
front_matter_title?: string;
|
||||
/**
|
||||
* Heading level
|
||||
*/
|
||||
level?: number;
|
||||
};
|
||||
/**
|
||||
* MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.37.4/doc/md042.md
|
||||
|
|
|
|||
|
|
@ -3,6 +3,26 @@
|
|||
import { addErrorContext, frontMatterHasTitle } from "../helpers/helpers.cjs";
|
||||
import { filterByTypes, getHeadingLevel, getHtmlTagInfo, isHtmlFlowComment, nonContentTokens } from "../helpers/micromark-helpers.cjs";
|
||||
|
||||
const headingTagNameRe = /^h[1-6]$/;
|
||||
|
||||
/**
|
||||
* Gets the HTML tag name of an htmlFlow token.
|
||||
*
|
||||
* @param {import("markdownlint").MicromarkToken} token Micromark Token.
|
||||
* @returns {string | null} Tag name.
|
||||
*/
|
||||
function getHtmlFlowTagName(token) {
|
||||
const { children, type } = token;
|
||||
if (type === "htmlFlow") {
|
||||
const htmlTexts = filterByTypes(children, [ "htmlText" ], true);
|
||||
const tagInfo = (htmlTexts.length > 0) && getHtmlTagInfo(htmlTexts[0]);
|
||||
if (tagInfo) {
|
||||
return tagInfo.name.toLowerCase();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @type {import("markdownlint").Rule} */
|
||||
export default {
|
||||
"names": [ "MD041", "first-line-heading", "first-line-h1" ],
|
||||
|
|
@ -10,6 +30,7 @@ export default {
|
|||
"tags": [ "headings" ],
|
||||
"parser": "micromark",
|
||||
"function": function MD041(params, onError) {
|
||||
const allowPreamble = !!params.config.allow_preamble;
|
||||
const level = Number(params.config.level || 1);
|
||||
const { tokens } = params.parsers.micromark;
|
||||
if (
|
||||
|
|
@ -18,22 +39,33 @@ export default {
|
|||
params.config.front_matter_title
|
||||
)
|
||||
) {
|
||||
let errorLineNumber = 0;
|
||||
for (const token of tokens) {
|
||||
if (!nonContentTokens.has(token.type) && !isHtmlFlowComment(token)) {
|
||||
let isError = true;
|
||||
if ((token.type === "atxHeading") || (token.type === "setextHeading")) {
|
||||
isError = (getHeadingLevel(token) !== level);
|
||||
} else if (token.type === "htmlFlow") {
|
||||
const htmlTexts = filterByTypes(token.children, [ "htmlText" ], true);
|
||||
const tagInfo = (htmlTexts.length > 0) && getHtmlTagInfo(htmlTexts[0]);
|
||||
isError = !tagInfo || (tagInfo.name.toLowerCase() !== `h${level}`);
|
||||
const { startLine, type } = token;
|
||||
if (!nonContentTokens.has(type) && !isHtmlFlowComment(token)) {
|
||||
let tagName = null;
|
||||
if ((type === "atxHeading") || (type === "setextHeading")) {
|
||||
// First heading needs to have the expected level
|
||||
if (getHeadingLevel(token) !== level) {
|
||||
errorLineNumber = startLine;
|
||||
}
|
||||
break;
|
||||
} else if ((tagName = getHtmlFlowTagName(token)) && headingTagNameRe.test(tagName)) {
|
||||
// First HTML element needs to have an <h?> with the expected level
|
||||
if (tagName !== `h${level}`) {
|
||||
errorLineNumber = startLine;
|
||||
}
|
||||
break;
|
||||
} else if (!allowPreamble) {
|
||||
// First non-content needs to be a heading with the expected level
|
||||
errorLineNumber = startLine;
|
||||
break;
|
||||
}
|
||||
if (isError) {
|
||||
addErrorContext(onError, token.startLine, params.lines[token.startLine - 1]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (errorLineNumber > 0) {
|
||||
addErrorContext(onError, errorLineNumber, params.lines[errorLineNumber - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue