Update MD018/MD019/MD020/MD021 to look specifically for "space" characters (space or tab) instead of RegExp's "\s" characters per CommonMark specification (fixes #367).

This commit is contained in:
David Anson 2021-02-03 22:05:07 -08:00
parent d2d4b310b9
commit 5aef3a4a51
6 changed files with 50 additions and 8 deletions

View file

@ -2368,7 +2368,7 @@ module.exports = {
"function": function MD018(params, onError) { "function": function MD018(params, onError) {
forEachLine(lineMetadata(), function (line, lineIndex, inCode) { forEachLine(lineMetadata(), function (line, lineIndex, inCode) {
if (!inCode && if (!inCode &&
/^#+[^#\s]/.test(line) && /^#+[^# \t]/.test(line) &&
!/#\s*$/.test(line) && !/#\s*$/.test(line) &&
!line.startsWith("#️⃣")) { !line.startsWith("#️⃣")) {
var hashCount = /^#+/.exec(line)[0].length; var hashCount = /^#+/.exec(line)[0].length;
@ -2402,7 +2402,7 @@ module.exports = {
filterTokens(params, "heading_open", function (token) { filterTokens(params, "heading_open", function (token) {
if (headingStyleFor(token) === "atx") { if (headingStyleFor(token) === "atx") {
var line = token.line, lineNumber = token.lineNumber; var line = token.line, lineNumber = token.lineNumber;
var match = /^(#+)(\s{2,})(?:\S)/.exec(line); var match = /^(#+)([ \t]{2,})(?:\S)/.exec(line);
if (match) { if (match) {
var hashLength = match[1]["length"], spacesLength = match[2]["length"]; var hashLength = match[1]["length"], spacesLength = match[2]["length"];
addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], { addErrorContext(onError, lineNumber, line.trim(), null, null, [1, hashLength + spacesLength + 1], {
@ -2436,7 +2436,7 @@ module.exports = {
"function": function MD020(params, onError) { "function": function MD020(params, onError) {
forEachLine(lineMetadata(), function (line, lineIndex, inCode) { forEachLine(lineMetadata(), function (line, lineIndex, inCode) {
if (!inCode) { if (!inCode) {
var match = /^(#+)(\s*)([^#]*?[^#\\])(\s*)((?:\\#)?)(#+)(\s*)$/.exec(line); var match = /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line);
if (match) { if (match) {
var leftHash = match[1], leftSpaceLength = match[2]["length"], content = match[3], rightSpaceLength = match[4]["length"], rightEscape = match[5], rightHash = match[6], trailSpaceLength = match[7]["length"]; var leftHash = match[1], leftSpaceLength = match[2]["length"], content = match[3], rightSpaceLength = match[4]["length"], rightEscape = match[5], rightHash = match[6], trailSpaceLength = match[7]["length"];
var leftHashLength = leftHash.length; var leftHashLength = leftHash.length;
@ -2487,7 +2487,7 @@ module.exports = {
filterTokens(params, "heading_open", function (token) { filterTokens(params, "heading_open", function (token) {
if (headingStyleFor(token) === "atx_closed") { if (headingStyleFor(token) === "atx_closed") {
var line = token.line, lineNumber = token.lineNumber; var line = token.line, lineNumber = token.lineNumber;
var match = /^(#+)(\s+)([^#]+?)(\s+)(#+)(\s*)$/.exec(line); var match = /^(#+)([ \t]+)([^#]+?)([ \t]+)(#+)(\s*)$/.exec(line);
if (match) { if (match) {
var leftHash = match[1], leftSpaceLength = match[2]["length"], content = match[3], rightSpaceLength = match[4]["length"], rightHash = match[5], trailSpaceLength = match[6]["length"]; var leftHash = match[1], leftSpaceLength = match[2]["length"], content = match[3], rightSpaceLength = match[4]["length"], rightHash = match[5], trailSpaceLength = match[6]["length"];
var left = leftSpaceLength > 1; var left = leftSpaceLength > 1;

View file

@ -12,7 +12,7 @@ module.exports = {
"function": function MD018(params, onError) { "function": function MD018(params, onError) {
forEachLine(lineMetadata(), (line, lineIndex, inCode) => { forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
if (!inCode && if (!inCode &&
/^#+[^#\s]/.test(line) && /^#+[^# \t]/.test(line) &&
!/#\s*$/.test(line) && !/#\s*$/.test(line) &&
!line.startsWith("#️⃣")) { !line.startsWith("#️⃣")) {
const hashCount = /^#+/.exec(line)[0].length; const hashCount = /^#+/.exec(line)[0].length;

View file

@ -13,7 +13,7 @@ module.exports = {
filterTokens(params, "heading_open", (token) => { filterTokens(params, "heading_open", (token) => {
if (headingStyleFor(token) === "atx") { if (headingStyleFor(token) === "atx") {
const { line, lineNumber } = token; const { line, lineNumber } = token;
const match = /^(#+)(\s{2,})(?:\S)/.exec(line); const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line);
if (match) { if (match) {
const [ const [
, ,

View file

@ -13,7 +13,7 @@ module.exports = {
forEachLine(lineMetadata(), (line, lineIndex, inCode) => { forEachLine(lineMetadata(), (line, lineIndex, inCode) => {
if (!inCode) { if (!inCode) {
const match = const match =
/^(#+)(\s*)([^#]*?[^#\\])(\s*)((?:\\#)?)(#+)(\s*)$/.exec(line); /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line);
if (match) { if (match) {
const [ const [
, ,

View file

@ -13,7 +13,7 @@ module.exports = {
filterTokens(params, "heading_open", (token) => { filterTokens(params, "heading_open", (token) => {
if (headingStyleFor(token) === "atx_closed") { if (headingStyleFor(token) === "atx_closed") {
const { line, lineNumber } = token; const { line, lineNumber } = token;
const match = /^(#+)(\s+)([^#]+?)(\s+)(#+)(\s*)$/.exec(line); const match = /^(#+)([ \t]+)([^#]+?)([ \t]+)(#+)(\s*)$/.exec(line);
if (match) { if (match) {
const [ const [
, ,

View file

@ -0,0 +1,42 @@
# Headings with invalid spaces
## Normal space
##  Normal outer non-breaking inner space
## Non-breaking space {MD018}
## Tab
## Normal space (both) ##
##  Normal outer non-breaking inner space (both)  ##
## Non-breaking space (left) {MD020} ##
## Tab (left) ##
## Non-breaking space (right) {MD020} ##
## Tab (right) ##
## Extra normal space {MD019}
##  Extra non-breaking space {MD018}
## Extra Tab {MD019}
## Extra Normal space (both) {MD021} ##
##  Extra non-breaking space (left) {MD020} ##
## Extra tab (left) {MD021} ##
## Extra non-breaking space (right) {MD020}  ##
## Extra tab (right) {MD021} ##
<!-- markdownlint-configure-file {
"heading-style": false,
"no-hard-tabs": false
} -->