Skip to content

Commit

Permalink
fix: fix to work some rules use ?= RegExp (#12)
Browse files Browse the repository at this point in the history
* test: add test for ?= RegExp

* fix(prh): fix to work rule that using `?=` RegExp

* fix: fix test case

* test: add more test case

* refactor: remove unused function
  • Loading branch information
azu authored Jan 13, 2017
1 parent 67a43f9 commit 4838d00
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 26 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
],
"dependencies": {
"prh": "^1.0.1",
"structured-source": "^3.0.2",
"textlint-rule-helper": "^2.0.0",
"untildify": "^3.0.2"
},
Expand Down
74 changes: 49 additions & 25 deletions src/prh-rule.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// LICENSE : MIT
"use strict";
import {RuleHelper} from "textlint-rule-helper";
import StructuredSource from "structured-source";
const prh = require("prh");
const path = require("path");
const untildify = require('untildify');
Expand Down Expand Up @@ -50,6 +49,47 @@ Please set .textlinrc:
`);
}
};

/**
* for each diff of changeSet
* @param {ChangeSet} changeSet
* @param {string} str
* @param {function({
matchStartIndex: number,
matchEndIndex: number,
actual: string
expected: string
})}onChangeOfMatch
*/
const forEachChange = (changeSet, str, onChangeOfMatch) => {
const sortedDiffs = changeSet.diffs.sort(function(a, b) {
return a.index - b.index;
});
let delta = 0;
sortedDiffs.forEach(function(diff) {
const result = diff.expected.replace(/\$([0-9]{1,2})/g, function(match, g1) {
const index = parseInt(g1);
if (index === 0 || (diff.matches.length - 1) < index) {
return match;
}
return diff.matches[index] || "";
});
// matchStartIndex/matchEndIndex value is original position, not replaced position
// textlint use original position
const matchStartIndex = diff.index;
const matchEndIndex = matchStartIndex + diff.matches[0].length;
// actual => expected
const actual = str.slice(diff.index + delta, diff.index + delta + diff.matches[0].length);
onChangeOfMatch({
matchStartIndex,
matchEndIndex,
actual: actual,
expected: result
});
str = str.slice(0, diff.index + delta) + result + str.slice(diff.index + delta + diff.matches[0].length);
delta += result.length - diff.matches[0].length;
});
};
function reporter(context, options = {}) {
assertOptions(options);
const textlintRcFilePath = context.config ? context.config.configFile : null;
Expand All @@ -69,33 +109,17 @@ function reporter(context, options = {}) {
if (helper.isChildNode(node, [Syntax.Link, Syntax.Image, Syntax.BlockQuote, Syntax.Emphasis])) {
return;
}
let text = getSource(node);
const text = getSource(node);
// to get position from index
let src = new StructuredSource(text);
let makeChangeSet = prhEngine.makeChangeSet(null, text);
makeChangeSet.diffs.forEach(function(changeSet) {
// | ----[match]------
var slicedText = text.slice(changeSet.index);
// | ----[match------|
var matchedText = slicedText.slice(0, changeSet.matches[0].length);
var expected = matchedText.replace(changeSet.pattern, changeSet.expected);
// Avoid accidental match(ignore case)
if (matchedText === expected) {
const makeChangeSet = prhEngine.makeChangeSet(null, text);
forEachChange(makeChangeSet, text, ({matchStartIndex, matchEndIndex, actual, expected}) => {
// If result is not changed, should not report
if (actual === expected) {
return;
}
/*
line start with 1
column start with 0
adjust position => line -1, column +0
*/
var position = src.indexToPosition(changeSet.index);

// line, column
report(node, new RuleError(matchedText + " => " + expected, {
line: position.line - 1,
column: position.column,
fix: fixer.replaceTextRange([changeSet.index, changeSet.index + matchedText.length], expected)
report(node, new RuleError(actual + " => " + expected, {
index: matchStartIndex,
fix: fixer.replaceTextRange([matchStartIndex, matchEndIndex], expected)
}));
});
}
Expand Down
79 changes: 79 additions & 0 deletions test/fixtures/example-prh.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
version: 1

rules:

# 大文字小文字全角半角の統一
- expected: Cookie
# 以下と等価 正規表現には強制でgフラグが付く
# - expected: Cookie
# pattern: "/[CcCc][OoOo][OoOo][KkKk][IiIi][EeEe]/g"
# options:
# wordBoundary: false
# specs: []

# 変換結果についてテストも書ける
- expected: jQuery
specs:
- from: jquery
to: jQuery
- from: JQUERY
to: jQuery

# 変換結果が期待通りではなかった場合、ルールのロードに失敗する つまり、ルールのテストが書ける
# - expected: JavaScript
# specs:
# - from: JAVASCRIPT
# to: JavaScprit # この場合はテスト側が間違ってる!
# Error: JavaScript spec failed. "JAVASCRIPT", expected "JavaScprit", but got "JavaScript", /[JjJj][AaAa][VvVv][AaAa][SsSs][CcCc][RrRr][IiIi][PpPp][TtTt]/g

# 表現の統一を図る
- expected: デフォルト
pattern: ディフォルト

# patternは複数記述可能 patterns としてもOK
- expected: ハードウェア
patterns:
- ハードウエアー # 正規表現に変換する都合上、より長いものを先に書いたほうがよい
- ハードウェアー
- ハードウエア

# patternには正規表現が利用可能
- expected: ($1)
pattern: /\(([^)]+)\)/
specs:
# 半角括弧を全角括弧へ
- from: (そのとおり)
to: (そのとおり)

# 否定戻り先読みが欲しいがJSにはない… regexpMustEmptyで、特定のキャプチャグループが空であることを指定して代用とする
- expected: ソフトウェア
pattern: /(日経)?ソフトウエア/
regexpMustEmpty: $1
specs:
# 普通に変換
- from: 広義のソフトウエア
to: 広義のソフトウェア
# 日経ソフトウエア(書名)は変換しない
- from: 日経ソフトウエア
to: 日経ソフトウエア

# 長音の統一には否定後読みを活用する そうしないと サーバー が サーバーー にされてしまったりする
- expected: サーバー
pattern: /サーバ(?!ー)/
specs:
- from: サーバ
to: サーバー

# 単語境界の区別
- expected: js
# pattern: "/\b[JjJj][SsSs]\b/g" # と等価 \b が前後に付与される
options:
wordBoundary: true
specs:
- from: foo JS bar
to: foo js bar
- from: foo altJS bar
to: foo altJS bar
# 日本語+単語境界の仕様は自分で調べてね…!
- from: 今日もJS祭り
to: 今日もjs祭り
22 changes: 22 additions & 0 deletions test/fixtures/prefer-regexp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 1

rules:
- prh: 「行う」「行なう」は開く。
expected: おこな
pattern: /(おこな|行な?)(?=[わいっうえお])/
specs:
- from: 行わない
to: おこなわない
- from: 行います
to: おこないます
- from: 行うとき
to: おこなうとき
- from: 行えば
to: おこなえば
- from: 行なう
to: おこなう
- from: おこなう
to: おこなう
# チェックされなくてよい部分
- from: 行く
to: 行く
179 changes: 179 additions & 0 deletions test/prh-rule-tester-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,185 @@ tester.run("prh", rule, {
column: 1
}
]
},
{
text: "行う、行なう、おこなう。行って、行わない、行ないます。",
output: "おこなう、おこなう、おこなう。おこなって、おこなわない、おこないます。",
options: {
"rulePaths": [__dirname + "/fixtures/prefer-regexp.yml"]
},
errors: [
{
"type": "lint",
"ruleId": "prh",
"message": "行 => おこな",
"index": 0,
"line": 1,
"column": 1,
"severity": 2,
"fix": {
"range": [
0,
1
],
"text": "おこな"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "行な => おこな",
"index": 3,
"line": 1,
"column": 4,
"severity": 2,
"fix": {
"range": [
3,
5
],
"text": "おこな"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "行 => おこな",
"index": 12,
"line": 1,
"column": 13,
"severity": 2,
"fix": {
"range": [
12,
13
],
"text": "おこな"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "行 => おこな",
"index": 16,
"line": 1,
"column": 17,
"severity": 2,
"fix": {
"range": [
16,
17
],
"text": "おこな"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "行な => おこな",
"index": 21,
"line": 1,
"column": 22,
"severity": 2,
"fix": {
"range": [
21,
23
],
"text": "おこな"
}
}
]
},
// example-prh.yml
{
text: "jqueryではクッキー。ディフォルトとハードウエアー。(そのとおり)\nサーバはサーバーサイドをjsする。",
output: "jQueryではクッキー。デフォルトとハードウェア。(そのとおり)\nサーバーはサーバーサイドをjsする。",
options: {
"rulePaths": [__dirname + "/fixtures/example-prh.yml"]
},
errors: [
{
"type": "lint",
"ruleId": "prh",
"message": "jquery => jQuery",
"index": 0,
"line": 1,
"column": 1,
"severity": 2,
"fix": {
"range": [
0,
6
],
"text": "jQuery"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "ディフォルト => デフォルト",
"index": 13,
"line": 1,
"column": 14,
"severity": 2,
"fix": {
"range": [
13,
19
],
"text": "デフォルト"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "ハードウエアー => ハードウェア",
"index": 20,
"line": 1,
"column": 21,
"severity": 2,
"fix": {
"range": [
20,
27
],
"text": "ハードウェア"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "(そのとおり) => (そのとおり)",
"index": 28,
"line": 1,
"column": 29,
"severity": 2,
"fix": {
"range": [
28,
35
],
"text": "(そのとおり)"
}
},
{
"type": "lint",
"ruleId": "prh",
"message": "サーバ => サーバー",
"index": 36,
"line": 2,
"column": 1,
"severity": 2,
"fix": {
"range": [
36,
39
],
"text": "サーバー"
}
}
]
}
]
});

0 comments on commit 4838d00

Please sign in to comment.