Skip to content

Commit 6ece8cd

Browse files
authored
feat: add skipPatterns options (#17)
BREAKING CHANGE: skip to count of url string link by default - Deprecated `exclusionPatterns` and use `skipPatterns` instead of it - Add `skipUrlStringLink` and Enable it by default
1 parent cd13e03 commit 6ece8cd

File tree

4 files changed

+90
-11
lines changed

4 files changed

+90
-11
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@ Add "sentence-length" to your `.textlintrc`.
2525
- default: 100
2626
- The total number of characters allowed on each sentences.
2727
- Sentence.length > 100 and throw Error
28-
- `exclusionPatterns`: `string[]`
28+
- `skipPatterns`: `string[]`
2929
- A strings that match the patterns is uncount of the sentence.
3030
- Set an array of RegExp-like string.
3131
- See https://github.com/textlint/regexp-string-matcher
32+
- `skipUrlStringLink`: `boolean`
33+
- Default: `true`
34+
- If it is `true`, skip url string link node like `<https:example.com>` or [https://example.com](https://example.com)
35+
- url string link is has the text which is same of url.
3236

3337
```
3438
{
@@ -47,7 +51,7 @@ Uncount `(...)` from `A sentence(...).`
4751
"rules": {
4852
"sentence-length": {
4953
"max": 100,
50-
"exclusionPatterns": [
54+
"skipPattern": [
5155
"/\\(.*\\)$\\./"
5256
]
5357

src/sentence-length.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { StringSource } from "textlint-util-to-string";
33
import { RuleHelper } from "textlint-rule-helper";
44
import { createRegExp } from "@textlint/regexp-string-matcher";
55
import { TextlintRuleReporter } from "@textlint/types";
6+
import { TxtNode, TxtParentNode } from "@textlint/ast-node-types";
67

78
function removeRangeFromString(text: string, regExpStrings: string[]) {
89
const patterns = regExpStrings.map((pattern) => {
@@ -17,20 +18,50 @@ function removeRangeFromString(text: string, regExpStrings: string[]) {
1718

1819
export type Options = {
1920
max?: number;
21+
/**
22+
* The strings that match following patterns is un-count of the sentence
23+
* See https://github.com/textlint/regexp-string-matcher
24+
*/
25+
skipPatterns?: string[];
26+
/**
27+
* If it is true, skip the count of following link node.
28+
*
29+
* [https://example.com](https://example.com)
30+
* <https://example.com>
31+
*
32+
* UrlStringLink is has the title which is same of href.
33+
*/
34+
skipUrlStringLink?: boolean;
35+
/**
36+
* @deprecated use skipPatterns
37+
*/
2038
exclusionPatterns?: string[];
2139
};
2240
const defaultOptions: Required<Options> = {
2341
max: 100,
24-
// The strings that match following patterns is uncount of the sentence
25-
// See https://github.com/textlint/regexp-string-matcher
42+
skipPatterns: [],
43+
skipUrlStringLink: true,
44+
/**
45+
* @deprecated
46+
*/
2647
exclusionPatterns: []
2748
};
2849

2950
const reporter: TextlintRuleReporter<Options> = (context, options = {}) => {
3051
const maxLength = options.max ?? defaultOptions.max;
31-
const exclusionPatterns = options.exclusionPatterns ?? defaultOptions.exclusionPatterns;
52+
const skipPattern = options.skipPatterns ?? options.exclusionPatterns ?? defaultOptions.skipPatterns;
53+
const skipUrlStringLink = options.skipUrlStringLink ?? defaultOptions.skipUrlStringLink;
3254
const helper = new RuleHelper(context);
3355
const { Syntax, RuleError, report } = context;
56+
const isUrlStringLink = (node: TxtNode | TxtParentNode): boolean => {
57+
if (node.type !== Syntax.Link) {
58+
return false;
59+
}
60+
const linkNode = node as TxtParentNode;
61+
const nodeText = new StringSource(linkNode).toString();
62+
return node.url === nodeText;
63+
};
64+
3465
// toPlainText
3566
return {
3667
[Syntax.Paragraph](node) {
@@ -47,17 +78,25 @@ const reporter: TextlintRuleReporter<Options> = (context, options = {}) => {
4778
paragraph.children
4879
.filter((sentence) => sentence.type === SentenceSyntax.Sentence)
4980
.forEach((sentence) => {
81+
const filteredSentence = skipUrlStringLink
82+
? {
83+
...sentence,
84+
children: sentence.children.filter((sentenceChildNode: TxtNode | TxtParentNode) => {
85+
return !isUrlStringLink(sentenceChildNode);
86+
})
87+
}
88+
: sentence;
5089
// @ts-expect-error: wrong types
51-
const source = new StringSource(sentence);
90+
const source = new StringSource(filteredSentence);
5291
const actualText = source.toString();
53-
const sentenceText = removeRangeFromString(actualText, exclusionPatterns);
92+
const sentenceText = removeRangeFromString(actualText, skipPattern);
5493
// larger than > 100
5594
const actualTextLength = actualText.length;
5695
const sentenceLength = sentenceText.length;
5796
if (sentenceLength > maxLength) {
58-
const startLine = sentence.loc.start.line;
97+
const startLine = filteredSentence.loc.start.line;
5998
report(
60-
sentence,
99+
filteredSentence,
61100
new RuleError(`Line ${startLine} sentence length(${
62101
sentenceLength !== actualTextLength
63102
? `${sentenceLength}, original:${actualTextLength}`

test/sentence-length-test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import TextLintTester from "textlint-tester";
22
import rule from "../src/sentence-length";
33
// @ts-expect-error: no types
44
import htmlPlugin from "textlint-plugin-html";
5+
56
const tester = new TextLintTester();
67

78
tester.run("textlint-rule-sentence-length", rule, {
@@ -42,7 +43,7 @@ tester.run("textlint-rule-sentence-length", rule, {
4243
text: "1234(56789)",
4344
options: {
4445
max: 5,
45-
exclusionPatterns: ["/\\(.*\\)$/"]
46+
skipPatterns: ["/\\(.*\\)$/"]
4647
}
4748
},
4849
{
@@ -53,6 +54,13 @@ tester.run("textlint-rule-sentence-length", rule, {
5354
max: 5
5455
}
5556
},
57+
{
58+
// url string link
59+
text: "[http://example.com](http://example.com)",
60+
options: {
61+
max: 5
62+
}
63+
},
5664
{
5765
// List
5866
text: '- [abc](http://example.com "abc")de',
@@ -202,7 +210,7 @@ Over 2 characters.`,
202210
text: "123456789(56789)",
203211
options: {
204212
max: 5,
205-
exclusionPatterns: ["/\\(.*\\)$/"]
213+
skipPatterns: ["/\\(.*\\)$/"]
206214
},
207215
errors: [
208216
{
@@ -211,6 +219,20 @@ Over 2 characters.`,
211219
"Over 4 characters."
212220
}
213221
]
222+
},
223+
{
224+
// url string link
225+
text: "TEST [http://example.com](http://example.com)",
226+
errors: [
227+
{
228+
message: `Line 1 sentence length(23) exceeds the maximum sentence length of 5.
229+
Over 18 characters.`
230+
}
231+
],
232+
options: {
233+
max: 5,
234+
skipUrlStringLink: false
235+
}
214236
}
215237
]
216238
});
@@ -239,6 +261,10 @@ tester.run(
239261
{
240262
text: "<p>this is a test.</p>",
241263
ext: ".html"
264+
},
265+
{
266+
text: "<p>TEST is <a href='https://example.com'>https://example.com</a></p>",
267+
ext: ".html"
242268
}
243269
],
244270
invalid: [

test/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../tsconfig.json",
3+
"compilerOptions": {
4+
"noEmit": true
5+
},
6+
"include": [
7+
"**/*",
8+
"../src/**/*"
9+
]
10+
}

0 commit comments

Comments
 (0)