Skip to content

add ornate parenthesis #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ textlint rule that check unmatched pairs like `(` and `]`
- 隅付き括弧【】: `【` and `】`
- double guillemet: `«` and `»`
- single guillemet: `‹` and `›`
- ornate parenthesis `﴾` and `﴿`

## Examples

Expand Down Expand Up @@ -53,6 +54,20 @@ Via `.textlintrc`(Recommended)
}
```

Some pair characters like the ornate parenthesis `﴾﴿` are strictly left or right oriented in every context.
To use such characters in rtl context, you need to reverse their usage.
You can use this rule by turning on the rtl option:

```json
{
"rules": {
"@textlint-rule/no-unmatched-pair": {
"rtl": true
}
}
}
```

Via CLI

```
Expand Down
42 changes: 28 additions & 14 deletions src/parser/PairMaker.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* https://ja.wikipedia.org/wiki/%E6%8B%AC%E5%BC%A7
*/
/**
* @typedef {{key:string,start:string,end:string}[]} PairMark
* @typedef {{key:string,start:string,end:string,reverseInRtl:boolean}[]} PairMark
*/
const PAIR_MARKS = [
{
Expand Down Expand Up @@ -76,54 +76,68 @@ const PAIR_MARKS = [
key: "single guillemet ‹›",
start: "‹",
end: "›"
},
{
key: "ornate parenthesis ﴾﴿",
start: "﴾",
end: "﴿",
reverseInRtl: true
}
];

// create entries
// [start.key, mark]
// [end.key, mark]
const PAIR_MARKS_ENTRIES = PAIR_MARKS.map((mark) => {
return [
[mark.start, mark],
[mark.end, mark]
];
}).flat(1);
const PAIR_MARKS_ENTRIES = (rtl) =>
PAIR_MARKS.map((mark) => {
const newMark = Object.assign({}, mark);
if (rtl && newMark.reverseInRtl) {
[newMark.start, newMark.end] = [newMark.end, newMark.start];
}

return [
[newMark.start, newMark],
[newMark.end, newMark]
];
}).flat(1);

/**
* Optimized Map
* @type Map<string, {key:string,start:string,end:string}>
* @type Map<string, {key:string,start:string,end:string,reverseInRtl:boolean}>
*/
const PAIR_MARKS_KEY_Map = new Map(PAIR_MARKS_ENTRIES);
const matchPair = (string) => {
const createPairMarksKeyMap = (rtl) => new Map(PAIR_MARKS_ENTRIES(rtl));
const matchPair = (string, rtl) => {
const PAIR_MARKS_KEY_Map = createPairMarksKeyMap(rtl);
return PAIR_MARKS_KEY_Map.get(string);
};
// For readme
// console.log(PAIR_MARKS.map(pair => `- ${pair.key}: \`${pair.start}\` and \`${pair.end}\``).join("\n"));
export class PairMaker {
/**
* @param {import("./SourceCode").SourceCode} sourceCode
* @param {boolean} rtl
* @returns
*/
mark(sourceCode) {
mark(sourceCode, rtl) {
const string = sourceCode.read();
if (!string) {
return;
}

const matchedPair = matchPair(string);
const matchedPair = matchPair(string, rtl);
if (!matchedPair) {
return;
}
// support nested pair
// {"{test}"}
if (sourceCode.isInContext(matchedPair)) {
// check that string is end mark?
const pair = PAIR_MARKS.find((pair) => pair.end === string);
const pair = PAIR_MARKS.find((pair) => (rtl && pair.reverseInRtl ? pair.start : pair.end === string));
if (pair) {
sourceCode.leaveContext(pair);
}
} else {
const pair = PAIR_MARKS.find((pair) => pair.start === string);
const pair = PAIR_MARKS.find((pair) => (rtl && pair.reverseInRtl ? pair.end : pair.start === string));
if (pair) {
sourceCode.enterContext(pair);
}
Expand Down
4 changes: 2 additions & 2 deletions src/textlint-rule-no-unmatched-pair.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PairMaker } from "./parser/PairMaker.js";
import { SourceCode } from "./parser/SourceCode.js";
import { IgnoreNodeManager } from "textlint-rule-helper";

const report = (context) => {
const report = (context, options) => {
const { Syntax, report, RuleError } = context;
const ignoreNodeManager = new IgnoreNodeManager();
return {
Expand All @@ -30,7 +30,7 @@ const report = (context) => {
const characterIndex = sentenceIndex + source.index;
// console.log(characterIndex, source.text[source.index], ignoreNodeManager.isIgnoredIndex(characterIndex));
if (!ignoreNodeManager.isIgnoredIndex(characterIndex)) {
pairMaker.mark(source);
pairMaker.mark(source, options.rtl);
}
source.peek();
}
Expand Down
30 changes: 29 additions & 1 deletion test/textlint-rule-no-unmatched-pair-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ tester.run("textlint-rule-no-unmatched-pair", rule, {
`> [!NOTE]
> some content`,
`Paul a dit : « Je viendrai demain » .`,
`Elle a écrit: « L’article est intitulé ‹ La technologie aujourd’hui › » .`
`Elle a écrit: « L’article est intitulé ‹ La technologie aujourd’hui › » .`,
`a test for ﴾ornate﴿ parenthesis`,
{
text: `كانت آية ﴿اقرأ﴾ أول آية نزلت من القرآن`,
options: {
rtl: true
}
}
],
invalid: [
{
Expand Down Expand Up @@ -115,6 +122,27 @@ This pair mark is called double quote.`
column: 41
}
]
},
{
text: `a test for ﴾ornate parenthesis`,
errors: [
{
line: 1,
column: 13
}
]
},
{
text: `كانت آية ﴿اقرأ أول آية نزلت من القرآن`,
options: {
rtl: true
},
errors: [
{
line: 1,
column: 11
}
]
}
]
});
Loading