Skip to content

Commit 4129c90

Browse files
committed
support reversed characters in RTL
1 parent 7f582b9 commit 4129c90

File tree

4 files changed

+59
-18
lines changed

4 files changed

+59
-18
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ Via `.textlintrc`(Recommended)
5454
}
5555
```
5656

57+
Some pair characters like the ornate parenthesis `﴾﴿` are strictly left or right oriented in every context.
58+
To use such characters in rtl context, you need to reverse their usage.
59+
You can use this rule by turning on the rtl option:
60+
61+
```json
62+
{
63+
"rules": {
64+
"@textlint-rule/no-unmatched-pair": {
65+
"rtl": true
66+
}
67+
}
68+
}
69+
```
70+
5771
Via CLI
5872

5973
```

src/parser/PairMaker.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* https://ja.wikipedia.org/wiki/%E6%8B%AC%E5%BC%A7
1010
*/
1111
/**
12-
* @typedef {{key:string,start:string,end:string}[]} PairMark
12+
* @typedef {{key:string,start:string,end:string,reverseInRtl:boolean}[]} PairMark
1313
*/
1414
const PAIR_MARKS = [
1515
{
@@ -80,55 +80,64 @@ const PAIR_MARKS = [
8080
{
8181
key: "ornate parenthesis ﴾﴿",
8282
start: "﴾",
83-
end: "﴿"
83+
end: "﴿",
84+
reverseInRtl: true
8485
}
8586
];
8687

8788
// create entries
8889
// [start.key, mark]
8990
// [end.key, mark]
90-
const PAIR_MARKS_ENTRIES = PAIR_MARKS.map((mark) => {
91-
return [
92-
[mark.start, mark],
93-
[mark.end, mark]
94-
];
95-
}).flat(1);
91+
const PAIR_MARKS_ENTRIES = (rtl) =>
92+
PAIR_MARKS.map((mark) => {
93+
const newMark = Object.assign({}, mark);
94+
if (rtl && newMark.reverseInRtl) {
95+
[newMark.start, newMark.end] = [newMark.end, newMark.start];
96+
}
97+
98+
return [
99+
[newMark.start, newMark],
100+
[newMark.end, newMark]
101+
];
102+
}).flat(1);
96103

97104
/**
98105
* Optimized Map
99-
* @type Map<string, {key:string,start:string,end:string}>
106+
* @type Map<string, {key:string,start:string,end:string,reverseInRtl:boolean}>
100107
*/
101-
const PAIR_MARKS_KEY_Map = new Map(PAIR_MARKS_ENTRIES);
102-
const matchPair = (string) => {
108+
const createPairMarksKeyMap = (rtl) => new Map(PAIR_MARKS_ENTRIES(rtl));
109+
const matchPair = (string, rtl) => {
110+
const PAIR_MARKS_KEY_Map = createPairMarksKeyMap(rtl);
103111
return PAIR_MARKS_KEY_Map.get(string);
104112
};
105113
// For readme
106114
// console.log(PAIR_MARKS.map(pair => `- ${pair.key}: \`${pair.start}\` and \`${pair.end}\``).join("\n"));
107115
export class PairMaker {
108116
/**
109117
* @param {import("./SourceCode").SourceCode} sourceCode
118+
* @param {boolean} rtl
110119
* @returns
111120
*/
112-
mark(sourceCode) {
121+
mark(sourceCode, rtl) {
113122
const string = sourceCode.read();
114123
if (!string) {
115124
return;
116125
}
117126

118-
const matchedPair = matchPair(string);
127+
const matchedPair = matchPair(string, rtl);
119128
if (!matchedPair) {
120129
return;
121130
}
122131
// support nested pair
123132
// {"{test}"}
124133
if (sourceCode.isInContext(matchedPair)) {
125134
// check that string is end mark?
126-
const pair = PAIR_MARKS.find((pair) => pair.end === string);
135+
const pair = PAIR_MARKS.find((pair) => (rtl && pair.reverseInRtl ? pair.start : pair.end === string));
127136
if (pair) {
128137
sourceCode.leaveContext(pair);
129138
}
130139
} else {
131-
const pair = PAIR_MARKS.find((pair) => pair.start === string);
140+
const pair = PAIR_MARKS.find((pair) => (rtl && pair.reverseInRtl ? pair.end : pair.start === string));
132141
if (pair) {
133142
sourceCode.enterContext(pair);
134143
}

src/textlint-rule-no-unmatched-pair.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { PairMaker } from "./parser/PairMaker.js";
44
import { SourceCode } from "./parser/SourceCode.js";
55
import { IgnoreNodeManager } from "textlint-rule-helper";
66

7-
const report = (context) => {
7+
const report = (context, options) => {
88
const { Syntax, report, RuleError } = context;
99
const ignoreNodeManager = new IgnoreNodeManager();
1010
return {
@@ -30,7 +30,7 @@ const report = (context) => {
3030
const characterIndex = sentenceIndex + source.index;
3131
// console.log(characterIndex, source.text[source.index], ignoreNodeManager.isIgnoredIndex(characterIndex));
3232
if (!ignoreNodeManager.isIgnoredIndex(characterIndex)) {
33-
pairMaker.mark(source);
33+
pairMaker.mark(source, options.rtl);
3434
}
3535
source.peek();
3636
}

test/textlint-rule-no-unmatched-pair-test.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@ tester.run("textlint-rule-no-unmatched-pair", rule, {
4040
> some content`,
4141
`Paul a dit : « Je viendrai demain » .`,
4242
`Elle a écrit: « L’article est intitulé ‹ La technologie aujourd’hui › » .`,
43-
`a test for ﴾ornate﴿ parenthesis`
43+
`a test for ﴾ornate﴿ parenthesis`,
44+
{
45+
text: `كانت آية ﴿اقرأ﴾ أول آية نزلت من القرآن`,
46+
options: {
47+
rtl: true
48+
}
49+
}
4450
],
4551
invalid: [
4652
{
@@ -125,6 +131,18 @@ This pair mark is called double quote.`
125131
column: 13
126132
}
127133
]
134+
},
135+
{
136+
text: `كانت آية ﴿اقرأ أول آية نزلت من القرآن`,
137+
options: {
138+
rtl: true
139+
},
140+
errors: [
141+
{
142+
line: 1,
143+
column: 11
144+
}
145+
]
128146
}
129147
]
130148
});

0 commit comments

Comments
 (0)