2018-01-21 21:44:25 -08:00
|
|
|
// @ts-check
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2024-08-13 20:57:00 -07:00
|
|
|
const { addErrorDetailIf } = require("../helpers");
|
|
|
|
const { referenceLinkImageData } = require("./cache");
|
|
|
|
const { addRangeToSet, filterByTypes, getDescendantsByType } = require("../helpers/micromark.cjs");
|
2018-01-21 21:44:25 -08:00
|
|
|
|
2019-12-12 21:22:45 -08:00
|
|
|
const longLineRePrefix = "^.{";
|
|
|
|
const longLineRePostfixRelaxed = "}.*\\s.*$";
|
|
|
|
const longLineRePostfixStrict = "}.+$";
|
2022-12-19 21:51:18 -08:00
|
|
|
const sternModeRe = /^(?:[#>\s]*\s)?\S*$/;
|
2018-01-21 21:44:25 -08:00
|
|
|
|
2024-02-27 20:42:09 -08:00
|
|
|
// eslint-disable-next-line jsdoc/valid-types
|
|
|
|
/** @type import("./markdownlint").Rule */
|
2018-01-21 21:44:25 -08:00
|
|
|
module.exports = {
|
|
|
|
"names": [ "MD013", "line-length" ],
|
|
|
|
"description": "Line length",
|
|
|
|
"tags": [ "line_length" ],
|
2024-08-13 20:57:00 -07:00
|
|
|
"parser": "micromark",
|
2018-01-21 21:44:25 -08:00
|
|
|
"function": function MD013(params, onError) {
|
2020-01-25 18:40:39 -08:00
|
|
|
const lineLength = Number(params.config.line_length || 80);
|
|
|
|
const headingLineLength =
|
|
|
|
Number(params.config.heading_line_length || lineLength);
|
|
|
|
const codeLineLength =
|
|
|
|
Number(params.config.code_block_line_length || lineLength);
|
2019-12-12 21:22:45 -08:00
|
|
|
const strict = !!params.config.strict;
|
2020-03-22 14:06:29 -07:00
|
|
|
const stern = !!params.config.stern;
|
2019-12-12 21:22:45 -08:00
|
|
|
const longLineRePostfix =
|
2020-03-22 14:06:29 -07:00
|
|
|
(strict || stern) ? longLineRePostfixStrict : longLineRePostfixRelaxed;
|
2019-03-26 22:34:19 -07:00
|
|
|
const longLineRe =
|
|
|
|
new RegExp(longLineRePrefix + lineLength + longLineRePostfix);
|
|
|
|
const longHeadingLineRe =
|
|
|
|
new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix);
|
2019-06-07 19:57:15 -07:00
|
|
|
const longCodeLineRe =
|
|
|
|
new RegExp(longLineRePrefix + codeLineLength + longLineRePostfix);
|
2018-04-27 22:05:34 -07:00
|
|
|
const codeBlocks = params.config.code_blocks;
|
|
|
|
const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks;
|
|
|
|
const tables = params.config.tables;
|
|
|
|
const includeTables = (tables === undefined) ? true : !!tables;
|
2023-11-09 20:05:30 -08:00
|
|
|
const headings = params.config.headings;
|
2018-04-27 22:05:34 -07:00
|
|
|
const includeHeadings = (headings === undefined) ? true : !!headings;
|
2024-08-13 20:57:00 -07:00
|
|
|
const { tokens } = params.parsers.micromark;
|
|
|
|
const headingLineNumbers = new Set();
|
|
|
|
for (const heading of filterByTypes(tokens, [ "atxHeading", "setextHeading" ])) {
|
|
|
|
addRangeToSet(headingLineNumbers, heading.startLine, heading.endLine);
|
|
|
|
}
|
|
|
|
const codeBlockLineNumbers = new Set();
|
|
|
|
for (const codeBlock of filterByTypes(tokens, [ "codeFenced", "codeIndented" ])) {
|
|
|
|
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
|
|
|
|
}
|
|
|
|
const tableLineNumbers = new Set();
|
|
|
|
for (const table of filterByTypes(tokens, [ "table" ])) {
|
|
|
|
addRangeToSet(tableLineNumbers, table.startLine, table.endLine);
|
|
|
|
}
|
|
|
|
const linkLineNumbers = new Set();
|
|
|
|
for (const link of filterByTypes(tokens, [ "autolink", "image", "link", "literalAutolink" ])) {
|
|
|
|
addRangeToSet(linkLineNumbers, link.startLine, link.endLine);
|
|
|
|
}
|
|
|
|
const paragraphDataLineNumbers = new Set();
|
|
|
|
for (const paragraph of filterByTypes(tokens, [ "paragraph" ])) {
|
|
|
|
for (const data of getDescendantsByType(paragraph, [ "data" ])) {
|
|
|
|
addRangeToSet(paragraphDataLineNumbers, data.startLine, data.endLine);
|
2022-06-08 22:10:27 -07:00
|
|
|
}
|
2024-08-13 20:57:00 -07:00
|
|
|
}
|
|
|
|
const linkOnlyLineNumbers = new Set();
|
|
|
|
for (const lineNumber of linkLineNumbers) {
|
|
|
|
if (!paragraphDataLineNumbers.has(lineNumber)) {
|
|
|
|
linkOnlyLineNumbers.add(lineNumber);
|
2018-01-21 21:44:25 -08:00
|
|
|
}
|
2024-08-13 20:57:00 -07:00
|
|
|
}
|
|
|
|
const definitionLineIndices = new Set(referenceLinkImageData().definitionLineIndices);
|
|
|
|
for (let lineIndex = 0; lineIndex < params.lines.length; lineIndex++) {
|
|
|
|
const line = params.lines[lineIndex];
|
2019-03-26 22:34:19 -07:00
|
|
|
const lineNumber = lineIndex + 1;
|
2024-08-13 20:57:00 -07:00
|
|
|
const isHeading = headingLineNumbers.has(lineNumber);
|
|
|
|
const inCode = codeBlockLineNumbers.has(lineNumber);
|
|
|
|
const inTable = tableLineNumbers.has(lineNumber);
|
2019-06-07 19:57:15 -07:00
|
|
|
const length = inCode ?
|
|
|
|
codeLineLength :
|
|
|
|
(isHeading ? headingLineLength : lineLength);
|
|
|
|
const lengthRe = inCode ?
|
|
|
|
longCodeLineRe :
|
|
|
|
(isHeading ? longHeadingLineRe : longLineRe);
|
2019-03-26 22:34:19 -07:00
|
|
|
if ((includeCodeBlocks || !inCode) &&
|
|
|
|
(includeTables || !inTable) &&
|
|
|
|
(includeHeadings || !isHeading) &&
|
2024-08-13 20:57:00 -07:00
|
|
|
!definitionLineIndices.has(lineIndex) &&
|
2019-12-12 21:22:45 -08:00
|
|
|
(strict ||
|
2020-03-22 14:06:29 -07:00
|
|
|
(!(stern && sternModeRe.test(line)) &&
|
2024-08-13 20:57:00 -07:00
|
|
|
!linkOnlyLineNumbers.has(lineNumber))) &&
|
2019-12-12 21:22:45 -08:00
|
|
|
lengthRe.test(line)) {
|
|
|
|
addErrorDetailIf(
|
|
|
|
onError,
|
|
|
|
lineNumber,
|
|
|
|
length,
|
|
|
|
line.length,
|
2024-06-08 14:44:49 -07:00
|
|
|
undefined,
|
|
|
|
undefined,
|
2024-08-13 20:57:00 -07:00
|
|
|
[ length + 1, line.length - length ]
|
|
|
|
);
|
2019-03-26 22:34:19 -07:00
|
|
|
}
|
2024-08-13 20:57:00 -07:00
|
|
|
}
|
2018-01-21 21:44:25 -08:00
|
|
|
}
|
|
|
|
};
|