mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-16 14:00:13 +01:00
Improve handling of nested tags and blocks by MD033/no-inline-html (fixes #179).
This commit is contained in:
parent
44fac78721
commit
4c7ffdd335
7 changed files with 372 additions and 18 deletions
|
|
@ -115,6 +115,19 @@ module.exports.escapeForRegExp = function escapeForRegExp(str) {
|
|||
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
};
|
||||
|
||||
// Un-escapes Markdown content (simple algorithm; not a parser)
|
||||
const escapedMarkdownRe = /\\./g;
|
||||
module.exports.unescapeMarkdown =
|
||||
function unescapeMarkdown(markdown, replacement) {
|
||||
return markdown.replace(escapedMarkdownRe, (match) => {
|
||||
const char = match[1];
|
||||
if ("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".includes(char)) {
|
||||
return replacement || char;
|
||||
}
|
||||
return match;
|
||||
});
|
||||
};
|
||||
|
||||
// Returns the indent for a token
|
||||
function indentFor(token) {
|
||||
const line = token.line.replace(/^[\s>]*(> |>)/, "");
|
||||
|
|
|
|||
38
lib/md033.js
38
lib/md033.js
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { addError, filterTokens, forEachInlineChild, newLineRe,
|
||||
rangeFromRegExp } = require("../helpers");
|
||||
const { addError, bareUrlRe, forEachLine, unescapeMarkdown } =
|
||||
require("../helpers");
|
||||
const { lineMetadata } = require("./cache");
|
||||
|
||||
const htmlRe = /<[^>]*>/;
|
||||
const htmlElementRe = /<(\w+)(?:[^>]*)?>/g;
|
||||
const linkDestinationRe = /]\(\s*$/;
|
||||
|
||||
module.exports = {
|
||||
"names": [ "MD033", "no-inline-html" ],
|
||||
|
|
@ -14,21 +16,21 @@ module.exports = {
|
|||
"function": function MD033(params, onError) {
|
||||
const allowedElements = (params.config.allowed_elements || [])
|
||||
.map((element) => element.toLowerCase());
|
||||
function forToken(token) {
|
||||
token.content.split(newLineRe)
|
||||
.forEach((line, offset) => {
|
||||
const allowed = (line.match(/<[^/\s>!]*/g) || [])
|
||||
.filter((element) => element.length > 1)
|
||||
.map((element) => element.slice(1).toLowerCase())
|
||||
.filter((element) => !allowedElements.includes(element));
|
||||
if (allowed.length) {
|
||||
addError(onError, token.lineNumber + offset,
|
||||
"Element: " + allowed[0], null,
|
||||
rangeFromRegExp(token.line, htmlRe));
|
||||
forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
|
||||
let match = null;
|
||||
// eslint-disable-next-line no-unmodified-loop-condition
|
||||
while (!inCode && (match = htmlElementRe.exec(line))) {
|
||||
const [ tag, element ] = match;
|
||||
if (!allowedElements.includes(element.toLowerCase()) &&
|
||||
!tag.endsWith("\\>") && !bareUrlRe.test(tag)) {
|
||||
const prefix = line.substring(0, match.index);
|
||||
if (!linkDestinationRe.test(prefix) &&
|
||||
!unescapeMarkdown(prefix + "<", "_").endsWith("_")) {
|
||||
addError(onError, lineIndex + 1, "Element: " + element,
|
||||
null, [ match.index + 1, tag.length ]);
|
||||
}
|
||||
});
|
||||
}
|
||||
filterTokens(params, "html_block", forToken);
|
||||
forEachInlineChild(params, "html_inline", forToken);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
9
test/detailed-results-html-tags.json
Normal file
9
test/detailed-results-html-tags.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"default": true,
|
||||
"MD033": {
|
||||
"allowed_elements": [
|
||||
"strong"
|
||||
]
|
||||
},
|
||||
"MD046": false
|
||||
}
|
||||
81
test/detailed-results-html-tags.md
Normal file
81
test/detailed-results-html-tags.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# Detailed HTML Results
|
||||
|
||||
Text
|
||||
|
||||
<em>Block block</em>
|
||||
|
||||
Text <em>inline inline</em> text
|
||||
|
||||
Text
|
||||
|
||||
<strong>Block block</strong>
|
||||
|
||||
Text <strong>inline inline</strong> text
|
||||
|
||||
Text
|
||||
|
||||
<p>
|
||||
Block
|
||||
block <em>block</em> block
|
||||
block
|
||||
block <strong>block</strong> block
|
||||
block
|
||||
block <em>block</em> block <strong>block</strong> block
|
||||
block <strong>block</strong> block <em>block</em> block
|
||||
</p>
|
||||
|
||||
Text
|
||||
|
||||
<strong><em>Block</em> block</strong>
|
||||
|
||||
Text <strong><em>inline</em> inline</strong> text
|
||||
|
||||
Text
|
||||
|
||||
<em><strong>Block</strong> block</em>
|
||||
|
||||
Text <em><strong>inline</strong> inline</em> text
|
||||
|
||||
Text
|
||||
|
||||
Text <em>inline</em> text <strong>inline</strong> text <em>inline</em> text
|
||||
|
||||
Text <strong>inline</strong> text <em>inline</em> text <strong>inline</strong> text
|
||||
|
||||
Text
|
||||
|
||||
\<not>Block block\</not>
|
||||
|
||||
\\<problem>Block block\\</problem>
|
||||
|
||||
<not\>Block block</not\>
|
||||
|
||||
Text \<not>inline inline\</not> text
|
||||
|
||||
Text \\<problem>inline inline\\</problem> text
|
||||
|
||||
Text <not\>inline inline</not\> text
|
||||
|
||||
Text
|
||||
|
||||
> Text <em>inline inline</em> text
|
||||
> text <strong>inline inline</strong> text
|
||||
|
||||
Text
|
||||
|
||||
Text <em>inline inline</em> text
|
||||
text <strong>inline inline</strong> text
|
||||
|
||||
Text
|
||||
|
||||
```html
|
||||
Text <em>inline inline</em> text
|
||||
text <strong>inline inline</strong> text
|
||||
```
|
||||
|
||||
Text
|
||||
|
||||
Text <a href="#anchor">inline</a> text
|
||||
text <img src="src.png"/> text
|
||||
|
||||
Text
|
||||
155
test/detailed-results-html-tags.results.json
Normal file
155
test/detailed-results-html-tags.results.json
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
[
|
||||
{
|
||||
"lineNumber": 5,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 1, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 7,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 6, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 17,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: p",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 1, 3 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 19,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 7, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 23,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 7, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 24,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 36, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 29,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 9, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 31,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 14, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 35,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 1, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 37,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 6, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 41,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 6, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 43,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 35, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 49,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: problem",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 3, 9 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 55,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: problem",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 8, 9 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 61,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: em",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 8, 4 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 78,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: a",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 6, 18 ]
|
||||
},
|
||||
{
|
||||
"lineNumber": 79,
|
||||
"ruleNames": [ "MD033", "no-inline-html" ],
|
||||
"ruleDescription": "Inline HTML",
|
||||
"ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md033",
|
||||
"errorDetail": "Element: img",
|
||||
"errorContext": null,
|
||||
"errorRange": [ 6, 20 ]
|
||||
}
|
||||
]
|
||||
|
|
@ -6,24 +6,56 @@
|
|||
|
||||
[text](<>) {MD042}
|
||||
|
||||
[text]( <> ) {MD042}
|
||||
|
||||
[text](<> "title") {MD042}
|
||||
|
||||
[text]( <> "title" ) {MD042}
|
||||
|
||||
[text](#) {MD042}
|
||||
|
||||
[text]( # ) {MD042}
|
||||
|
||||
[text](# "title") {MD042}
|
||||
|
||||
[text]( # "title" ) {MD042}
|
||||
|
||||
[text][frag] {MD042}
|
||||
|
||||
[text][ frag ] {MD042}
|
||||
|
||||
[frag]: #
|
||||
|
||||
## Non-empty links
|
||||
|
||||
[text](link)
|
||||
|
||||
[text]( link )
|
||||
|
||||
[text](link "title")
|
||||
|
||||
[text]( link "title" )
|
||||
|
||||
[text](<link>)
|
||||
|
||||
[text]( <link> )
|
||||
|
||||
[text](<link> "title")
|
||||
|
||||
[text]( <link> "title" )
|
||||
|
||||
[text](#frag)
|
||||
|
||||
[text]( #frag )
|
||||
|
||||
[text](#frag "title")
|
||||
|
||||
[text]( #frag "title" )
|
||||
|
||||
[text][ref]
|
||||
|
||||
[text][ ref ]
|
||||
|
||||
[ref]: link
|
||||
|
||||
[text]
|
||||
|
|
|
|||
|
|
@ -1406,6 +1406,68 @@ function clearHtmlCommentTextEmbedded(test) {
|
|||
test.done();
|
||||
};
|
||||
|
||||
module.exports.unescapeMarkdown = function unescapeMarkdown(test) {
|
||||
test.expect(7);
|
||||
// Test cases from https://spec.commonmark.org/0.29/#backslash-escapes
|
||||
const testCases = [
|
||||
[
|
||||
"\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;" +
|
||||
"\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~",
|
||||
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||
],
|
||||
[
|
||||
"\\→\\A\\a\\ \\3\\φ\\«",
|
||||
"\\→\\A\\a\\ \\3\\φ\\«"
|
||||
],
|
||||
[
|
||||
`\\*not emphasized*
|
||||
\\<br/> not a tag
|
||||
\\[not a link](/foo)
|
||||
\\\`not code\`
|
||||
1\\. not a list
|
||||
\\* not a list
|
||||
\\# not a heading
|
||||
\\[foo]: /url "not a reference"
|
||||
\\ö not a character entity`,
|
||||
`*not emphasized*
|
||||
<br/> not a tag
|
||||
[not a link](/foo)
|
||||
\`not code\`
|
||||
1. not a list
|
||||
* not a list
|
||||
# not a heading
|
||||
[foo]: /url "not a reference"
|
||||
ö not a character entity`
|
||||
],
|
||||
[
|
||||
"\\\\*emphasis*",
|
||||
"\\*emphasis*"
|
||||
],
|
||||
[
|
||||
`foo\\
|
||||
bar`,
|
||||
`foo\\
|
||||
bar`
|
||||
],
|
||||
[
|
||||
"Text \\<",
|
||||
"Text _",
|
||||
"_"
|
||||
],
|
||||
[
|
||||
"Text \\\\<",
|
||||
"Text _<",
|
||||
"_"
|
||||
]
|
||||
];
|
||||
testCases.forEach(function forTestCase(testCase) {
|
||||
const [ markdown, expected, replacement ] = testCase;
|
||||
const actual = helpers.unescapeMarkdown(markdown, replacement);
|
||||
test.equal(actual, expected);
|
||||
});
|
||||
test.done();
|
||||
};
|
||||
|
||||
module.exports.isBlankLine = function isBlankLine(test) {
|
||||
test.expect(25);
|
||||
const blankLines = [
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue