mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Reimplement helpers.forEachInlineCodeSpan for ~11% time reduction measured via profile-fixture.mjs on GitHub Codespaces.
This commit is contained in:
parent
d177ee2fc5
commit
6e8a0737b5
3 changed files with 67 additions and 116 deletions
|
@ -437,67 +437,39 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachInlineCodeSpan(input, handler) {
|
function forEachInlineCodeSpan(input, handler) {
|
||||||
let currentLine = 0;
|
const backtickRe = /`+/g;
|
||||||
let currentColumn = 0;
|
let match = null;
|
||||||
let index = 0;
|
const backticksLengthAndIndex = [];
|
||||||
while (index < input.length) {
|
while ((match = backtickRe.exec(input)) !== null) {
|
||||||
let startIndex = -1;
|
backticksLengthAndIndex.push([match[0].length, match.index]);
|
||||||
let startLine = -1;
|
}
|
||||||
let startColumn = -1;
|
const newLinesIndex = [];
|
||||||
let tickCount = 0;
|
while ((match = newLineRe.exec(input)) !== null) {
|
||||||
let currentTicks = 0;
|
newLinesIndex.push(match.index);
|
||||||
// Deliberate <= so trailing 0 completes the last span (ex: "text `code`")
|
}
|
||||||
// False-positive for js/index-out-of-bounds
|
let lineIndex = 0;
|
||||||
for (; index <= input.length; index++) {
|
let lineStartIndex = 0;
|
||||||
const char = input[index];
|
let k = 0;
|
||||||
// Parse backtick open/close
|
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) {
|
||||||
if (char === "`") {
|
const [startLength, startIndex] = backticksLengthAndIndex[i];
|
||||||
// Count backticks at start or end of code span
|
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) {
|
||||||
currentTicks++;
|
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) {
|
||||||
if ((startIndex === -1) || (startColumn === -1)) {
|
const [endLength, endIndex] = backticksLengthAndIndex[j];
|
||||||
startIndex = index + 1;
|
if (startLength === endLength) {
|
||||||
|
for (; k < newLinesIndex.length; k++) {
|
||||||
|
const newLineIndex = newLinesIndex[k];
|
||||||
|
if (startIndex < newLineIndex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lineIndex++;
|
||||||
|
lineStartIndex = newLineIndex + 1;
|
||||||
|
}
|
||||||
|
const columnIndex = startIndex - lineStartIndex + startLength;
|
||||||
|
handler(input.slice(startIndex + startLength, endIndex), lineIndex, columnIndex, startLength);
|
||||||
|
i = j;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if ((startIndex >= 0) &&
|
|
||||||
(startColumn >= 0) &&
|
|
||||||
(tickCount === currentTicks)) {
|
|
||||||
// Found end backticks; invoke callback for code span
|
|
||||||
handler(input.substring(startIndex, index - currentTicks), startLine, startColumn, tickCount);
|
|
||||||
startIndex = -1;
|
|
||||||
startColumn = -1;
|
|
||||||
}
|
|
||||||
else if ((startIndex >= 0) && (startColumn === -1)) {
|
|
||||||
// Found start backticks
|
|
||||||
tickCount = currentTicks;
|
|
||||||
startLine = currentLine;
|
|
||||||
startColumn = currentColumn;
|
|
||||||
}
|
|
||||||
// Not in backticks
|
|
||||||
currentTicks = 0;
|
|
||||||
}
|
|
||||||
if (char === "\n") {
|
|
||||||
// On next line
|
|
||||||
currentLine++;
|
|
||||||
currentColumn = 0;
|
|
||||||
}
|
|
||||||
else if ((char === "\\") &&
|
|
||||||
((startIndex === -1) || (startColumn === -1)) &&
|
|
||||||
(input[index + 1] !== "\n")) {
|
|
||||||
// Escape character outside code, skip next
|
|
||||||
index++;
|
|
||||||
currentColumn += 2;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// On next column
|
|
||||||
currentColumn++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (startIndex >= 0) {
|
|
||||||
// Restart loop after unmatched start backticks (ex: "`text``code``")
|
|
||||||
index = startIndex;
|
|
||||||
currentLine = startLine;
|
|
||||||
currentColumn = startColumn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -437,65 +437,44 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachInlineCodeSpan(input, handler) {
|
function forEachInlineCodeSpan(input, handler) {
|
||||||
let currentLine = 0;
|
const backtickRe = /`+/g;
|
||||||
let currentColumn = 0;
|
let match = null;
|
||||||
let index = 0;
|
const backticksLengthAndIndex = [];
|
||||||
while (index < input.length) {
|
while ((match = backtickRe.exec(input)) !== null) {
|
||||||
let startIndex = -1;
|
backticksLengthAndIndex.push([ match[0].length, match.index ]);
|
||||||
let startLine = -1;
|
}
|
||||||
let startColumn = -1;
|
const newLinesIndex = [];
|
||||||
let tickCount = 0;
|
while ((match = newLineRe.exec(input)) !== null) {
|
||||||
let currentTicks = 0;
|
newLinesIndex.push(match.index);
|
||||||
// Deliberate <= so trailing 0 completes the last span (ex: "text `code`")
|
}
|
||||||
// False-positive for js/index-out-of-bounds
|
let lineIndex = 0;
|
||||||
for (; index <= input.length; index++) {
|
let lineStartIndex = 0;
|
||||||
const char = input[index];
|
let k = 0;
|
||||||
// Parse backtick open/close
|
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) {
|
||||||
if (char === "`") {
|
const [ startLength, startIndex ] = backticksLengthAndIndex[i];
|
||||||
// Count backticks at start or end of code span
|
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) {
|
||||||
currentTicks++;
|
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) {
|
||||||
if ((startIndex === -1) || (startColumn === -1)) {
|
const [ endLength, endIndex ] = backticksLengthAndIndex[j];
|
||||||
startIndex = index + 1;
|
if (startLength === endLength) {
|
||||||
}
|
for (; k < newLinesIndex.length; k++) {
|
||||||
} else {
|
const newLineIndex = newLinesIndex[k];
|
||||||
if ((startIndex >= 0) &&
|
if (startIndex < newLineIndex) {
|
||||||
(startColumn >= 0) &&
|
break;
|
||||||
(tickCount === currentTicks)) {
|
}
|
||||||
// Found end backticks; invoke callback for code span
|
lineIndex++;
|
||||||
|
lineStartIndex = newLineIndex + 1;
|
||||||
|
}
|
||||||
|
const columnIndex = startIndex - lineStartIndex + startLength;
|
||||||
handler(
|
handler(
|
||||||
input.substring(startIndex, index - currentTicks),
|
input.slice(startIndex + startLength, endIndex),
|
||||||
startLine, startColumn, tickCount);
|
lineIndex,
|
||||||
startIndex = -1;
|
columnIndex,
|
||||||
startColumn = -1;
|
startLength
|
||||||
} else if ((startIndex >= 0) && (startColumn === -1)) {
|
);
|
||||||
// Found start backticks
|
i = j;
|
||||||
tickCount = currentTicks;
|
break;
|
||||||
startLine = currentLine;
|
|
||||||
startColumn = currentColumn;
|
|
||||||
}
|
}
|
||||||
// Not in backticks
|
|
||||||
currentTicks = 0;
|
|
||||||
}
|
}
|
||||||
if (char === "\n") {
|
|
||||||
// On next line
|
|
||||||
currentLine++;
|
|
||||||
currentColumn = 0;
|
|
||||||
} else if ((char === "\\") &&
|
|
||||||
((startIndex === -1) || (startColumn === -1)) &&
|
|
||||||
(input[index + 1] !== "\n")) {
|
|
||||||
// Escape character outside code, skip next
|
|
||||||
index++;
|
|
||||||
currentColumn += 2;
|
|
||||||
} else {
|
|
||||||
// On next column
|
|
||||||
currentColumn++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (startIndex >= 0) {
|
|
||||||
// Restart loop after unmatched start backticks (ex: "`text``code``")
|
|
||||||
index = startIndex;
|
|
||||||
currentLine = startLine;
|
|
||||||
currentColumn = startColumn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,7 +391,7 @@ test("forEachInlineCodeSpan", (t) => {
|
||||||
t.is(column, expectedColumn, input);
|
t.is(column, expectedColumn, input);
|
||||||
t.is(ticks, expectedTicks, input);
|
t.is(ticks, expectedTicks, input);
|
||||||
});
|
});
|
||||||
t.is(expecteds.length, 0, "length");
|
t.is(expecteds.shift(), undefined, input);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue