-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
single-sentence-per-line-rule.js
107 lines (98 loc) · 3.13 KB
/
single-sentence-per-line-rule.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
// @ts-check
"use strict";
// BUG: for some reason this rule does not detect sentences starting with *, _ or `
// so these have to be manually placed on new lines
const indentFor = (string, indentation) => {
const regex = new RegExp(
"^(?<indents>(" + indentation + ")*)(?<adds>- |> |>|\\* |\\d+\\. )?",
);
const match = regex.exec(string);
if (!match) {
return "";
}
let indentSize = 0;
if (match.groups?.indents) {
indentSize = match.groups.indents.length / indentation.length;
}
if (match.groups?.adds) {
if (match.groups.adds.includes(">")) {
return indentation.repeat(indentSize) + match.groups.adds;
}
indentSize++;
}
return indentation.repeat(indentSize);
};
const isAfterIgnoredWord = (ignoredWords, line, i) => {
for (const ignoredWord of ignoredWords) {
const lastWordInLine = line.substring(i - ignoredWord.length, i);
if (ignoredWord === lastWordInLine.toLowerCase()) {
return true;
}
}
return false;
};
module.exports = {
names: ["max-one-sentence-per-line"],
description: "Max 1 sentence should be on a line",
information: new URL(
"https://github.com/aepfli/markdownlint-rule-max-one-sentence-per-line",
),
tags: ["sentences"],
function: (params, onError) => {
const ignoredWords = params.config.ignored_words || [
"ie",
"i.e",
"eg",
"e.g",
"etc",
"ex",
"`assert",
"`panic",
];
const lineEndings = params.config.line_endings || [".", "?", "!"];
const sentenceStartRegex =
params.config.sentence_start || "^\\s+(\\w|[*_'\"`])";
const indentation = params.config.indentation || " ";
const sentenceStart = new RegExp(sentenceStartRegex);
const relevantTokens = [];
for (let i = 0; i < params.tokens.length; i++) {
const token = params.tokens[i];
if (
token.type === "paragraph_open" &&
params.tokens[i + 1].type === "inline"
) {
relevantTokens.push(params.tokens[i + 1]);
}
}
for (const relevantToken of relevantTokens) {
for (const token of relevantToken.children) {
const lineNumber = token.lineNumber;
if (token.type === "text") {
const content = token.content;
for (let i = 0; i < content.length - 2; i += 1) {
if (lineEndings.includes(content[i])) {
const sentence = sentenceStart.exec(content.substr(i + 1));
if (
sentence !== null &&
!isAfterIgnoredWord(ignoredWords, content, i)
) {
const spaces = sentence[1];
const pointInLine = token.line.indexOf(content) + i;
onError({
lineNumber, // Report error on paragraph start
detail: "Each sentence should be on its own line.",
fixInfo: {
editColumn: pointInLine + 2,
deleteCount: spaces.length,
insertText:
"\n" + indentFor(relevantToken.line, indentation),
}
});
}
}
}
}
}
}
},
};