-
-
Notifications
You must be signed in to change notification settings - Fork 757
/
Copy pathmd037.js
185 lines (181 loc) · 6.36 KB
/
md037.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// @ts-check
"use strict";
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine,
withinAnyRange } = require("../helpers");
const { htmlElementRanges, lineMetadata } = require("./cache");
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
const embeddedUnderscoreRe = /([A-Za-z\d])(_([A-Za-z\d]))+/g;
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
const leftSpaceRe = /^\s+/;
const rightSpaceRe = /\s+$/;
const tablePipeRe = /\|/;
const allUnderscoresRe = /_/g;
module.exports = {
"names": [ "MD037", "no-space-in-emphasis" ],
"description": "Spaces inside emphasis markers",
"tags": [ "whitespace", "emphasis" ],
"function": function MD037(params, onError) {
const exclusions = htmlElementRanges();
// eslint-disable-next-line init-declarations
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
pendingError = null;
// eslint-disable-next-line jsdoc/require-jsdoc
function resetRunTracking() {
emphasisIndex = -1;
emphasisLength = 0;
emphasisKind = "";
effectiveEmphasisLength = 0;
pendingError = null;
}
// eslint-disable-next-line jsdoc/require-jsdoc
function handleRunEnd(
line, lineIndex, contextLength, match, matchIndex, inTable
) {
// Close current run
let content = line.substring(emphasisIndex, matchIndex);
if (!emphasisLength) {
content = content.trimStart();
}
if (!match) {
content = content.trimEnd();
}
const leftSpace = leftSpaceRe.test(content);
const rightSpace = rightSpaceRe.test(content);
if (
(leftSpace || rightSpace) &&
(!inTable || !tablePipeRe.test(content))
) {
// Report the violation
const contextStart = emphasisIndex - emphasisLength;
const contextEnd = matchIndex + contextLength;
const column = contextStart + 1;
const length = contextEnd - contextStart;
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
const context = line.substring(contextStart, contextEnd);
const leftMarker = line.substring(contextStart, emphasisIndex);
const rightMarker = match ? (match[2] || match[3]) : "";
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
return [
onError,
lineIndex + 1,
context,
leftSpace,
rightSpace,
[ column, length ],
{
"editColumn": column,
"deleteCount": length,
"insertText": fixedText
}
];
}
}
return null;
}
// Initialize
const ignoreMarkersByLine = emphasisMarkersInContent(params);
resetRunTracking();
forEachLine(
lineMetadata(),
(line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) => {
const onItemStart = (inItem === 1);
if (
inCode ||
onFence ||
inTable ||
onBreak ||
onItemStart ||
isBlankLine(line)
) {
// Emphasis resets when leaving a block
resetRunTracking();
}
if (
inCode ||
onFence ||
onBreak ||
inMath
) {
// Emphasis has no meaning here
return;
}
let patchedLine = line.replace(
embeddedUnderscoreRe,
(match) => match.replace(allUnderscoresRe, " ")
);
if (onItemStart) {
// Trim overlapping '*' list item marker
patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
}
let match = null;
// Match all emphasis-looking runs in the line...
while ((match = emphasisRe.exec(patchedLine))) {
const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex];
const matchIndex = match.index + match[1].length;
if (ignoreMarkersForLine.includes(matchIndex)) {
// Ignore emphasis markers inside code spans and links
continue;
}
const matchLength = match[0].length - match[1].length;
const matchKind = (match[2] || match[3])[0];
if (emphasisIndex === -1) {
// New run
emphasisIndex = matchIndex + matchLength;
emphasisLength = matchLength;
emphasisKind = matchKind;
effectiveEmphasisLength = matchLength;
} else if (matchKind === emphasisKind) {
// Matching emphasis markers
if (matchLength === effectiveEmphasisLength) {
// Ending an existing run, report any pending error
if (pendingError) {
// @ts-ignore
addErrorContext(...pendingError);
pendingError = null;
}
const error = handleRunEnd(
line,
lineIndex,
effectiveEmphasisLength,
match,
matchIndex,
inTable
);
if (error) {
// @ts-ignore
addErrorContext(...error);
}
// Reset
resetRunTracking();
} else if (matchLength === 3) {
// Swap internal run length (1->2 or 2->1)
effectiveEmphasisLength = matchLength - effectiveEmphasisLength;
} else if (effectiveEmphasisLength === 3) {
// Downgrade internal run (3->1 or 3->2)
effectiveEmphasisLength -= matchLength;
} else {
// Upgrade to internal run (1->3 or 2->3)
effectiveEmphasisLength += matchLength;
}
// Back up one character so RegExp has a chance to match the
// next marker (ex: "**star**_underscore_")
if (emphasisRe.lastIndex > 1) {
emphasisRe.lastIndex--;
}
} else if (emphasisRe.lastIndex > 1) {
// Back up one character so RegExp has a chance to match the
// mis-matched marker (ex: "*text_*")
emphasisRe.lastIndex--;
}
}
if (emphasisIndex !== -1) {
pendingError = pendingError ||
handleRunEnd(line, lineIndex, 0, null, line.length, inTable);
// Adjust for pending run on new line
emphasisIndex = 0;
emphasisLength = 0;
}
}
);
}
};