2018-01-21 21:44:25 -08:00
|
|
|
// @ts-check
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2023-07-24 21:36:55 -07:00
|
|
|
const { addError } = require("../helpers");
|
2018-01-21 21:44:25 -08:00
|
|
|
|
2023-07-24 21:36:55 -07:00
|
|
|
const emphasisStartTextRe = /^(\S{1,3})(\s+)\S/;
|
|
|
|
const emphasisEndTextRe = /\S(\s+)(\S{1,3})$/;
|
2019-09-06 22:35:33 -07:00
|
|
|
|
2018-01-21 21:44:25 -08:00
|
|
|
module.exports = {
|
|
|
|
"names": [ "MD037", "no-space-in-emphasis" ],
|
|
|
|
"description": "Spaces inside emphasis markers",
|
|
|
|
"tags": [ "whitespace", "emphasis" ],
|
|
|
|
"function": function MD037(params, onError) {
|
2023-07-24 21:36:55 -07:00
|
|
|
|
|
|
|
// Initialize variables
|
|
|
|
const { lines, parsers } = params;
|
|
|
|
const emphasisTokensByMarker = new Map();
|
|
|
|
for (const marker of [ "_", "__", "___", "*", "**", "***" ]) {
|
|
|
|
emphasisTokensByMarker.set(marker, []);
|
2020-04-12 20:40:05 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
const pending = [ ...parsers.micromark.tokens ];
|
|
|
|
let token = null;
|
|
|
|
while ((token = pending.shift())) {
|
|
|
|
|
|
|
|
// Use reparsed children of htmlFlow tokens
|
|
|
|
if (token.type === "htmlFlow") {
|
|
|
|
pending.unshift(...token.htmlFlowChildren);
|
|
|
|
continue;
|
2020-04-12 20:40:05 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
pending.push(...token.children);
|
|
|
|
|
|
|
|
// Build lists of bare tokens for each emphasis marker type
|
|
|
|
for (const emphasisTokens of emphasisTokensByMarker.values()) {
|
|
|
|
emphasisTokens.length = 0;
|
2020-04-12 20:40:05 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
for (const child of token.children) {
|
|
|
|
const { text, type } = child;
|
|
|
|
if ((type === "data") && (text.length <= 3)) {
|
|
|
|
const emphasisTokens = emphasisTokensByMarker.get(text);
|
|
|
|
if (emphasisTokens) {
|
|
|
|
emphasisTokens.push(child);
|
|
|
|
}
|
2022-07-30 20:35:27 -07:00
|
|
|
}
|
2020-04-12 20:40:05 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
|
|
|
|
// Process bare tokens for each emphasis marker type
|
|
|
|
for (const emphasisTokens of emphasisTokensByMarker.values()) {
|
|
|
|
for (let i = 0; i + 1 < emphasisTokens.length; i += 2) {
|
|
|
|
|
|
|
|
// Process start token of start/end pair
|
|
|
|
const startToken = emphasisTokens[i];
|
|
|
|
const startText =
|
|
|
|
lines[startToken.startLine - 1].slice(startToken.startColumn - 1);
|
|
|
|
const startMatch = startText.match(emphasisStartTextRe);
|
|
|
|
if (startMatch) {
|
|
|
|
const [ startContext, startMarker, startSpaces ] = startMatch;
|
|
|
|
if ((startMarker === startToken.text) && (startSpaces.length > 0)) {
|
|
|
|
addError(
|
|
|
|
onError,
|
|
|
|
startToken.startLine,
|
|
|
|
undefined,
|
|
|
|
startContext,
|
|
|
|
[ startToken.startColumn, startContext.length ],
|
|
|
|
{
|
|
|
|
"editColumn": startToken.endColumn,
|
|
|
|
"deleteCount": startSpaces.length
|
|
|
|
}
|
2021-01-23 20:47:27 -08:00
|
|
|
);
|
2020-04-12 20:40:05 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Process end token of start/end pair
|
|
|
|
const endToken = emphasisTokens[i + 1];
|
|
|
|
const endText =
|
|
|
|
lines[endToken.startLine - 1].slice(0, endToken.endColumn - 1);
|
|
|
|
const endMatch = endText.match(emphasisEndTextRe);
|
|
|
|
if (endMatch) {
|
|
|
|
const [ endContext, endSpace, endMarker ] = endMatch;
|
|
|
|
if ((endMarker === endToken.text) && (endSpace.length > 0)) {
|
|
|
|
addError(
|
|
|
|
onError,
|
|
|
|
endToken.startLine,
|
|
|
|
undefined,
|
|
|
|
endContext,
|
|
|
|
[ endToken.endColumn - endContext.length, endContext.length ],
|
|
|
|
{
|
|
|
|
"editColumn": endToken.startColumn - endSpace.length,
|
|
|
|
"deleteCount": endSpace.length
|
|
|
|
}
|
|
|
|
);
|
2020-06-15 19:42:46 -07:00
|
|
|
}
|
2019-09-06 22:35:33 -07:00
|
|
|
}
|
2019-03-04 19:54:23 -08:00
|
|
|
}
|
2020-03-28 14:16:28 -07:00
|
|
|
}
|
2023-07-24 21:36:55 -07:00
|
|
|
}
|
2018-01-21 21:44:25 -08:00
|
|
|
}
|
|
|
|
};
|