1
1
// MIT © 2017 azu
2
2
"use strict" ;
3
+ const escapeStringRegexp = require ( 'escape-string-regexp' ) ;
3
4
const matchCaptureGroupAll = require ( "match-index" ) . matchCaptureGroupAll ;
4
5
const regx = require ( "regx" ) . default ;
5
6
// IME的に入力されそうな文字列
6
7
// 日本語 + 記号
7
- const japaneseRegExp = / (?: [ 々 〇 〻 \u3400 - \u4DBF \u4E00 - \u9FFF \uF900 - \uFAFF ] | [ \uD840 - \uD87F ] [ \uDC00 - \uDFFF ] | [ ぁ - ん ァ - ヶ ー 。 、 ・ − ] ) / ;
8
+ const japaneseRegExp = / (?: [ 々 〇 〻 \u3400 - \u4DBF \u4E00 - \u9FFF \uF900 - \uFAFF ] | [ \uD840 - \uD87F ] | [ \uFF00 - \uFFEF ] | [ \uDC00 - \uDFFF ] | [ ぁ - ん ァ - ヶ ー 。 、 ・ − ] ) / ;
8
9
// 半角/全角のアルファベットの正規表現
9
10
const alphabetPattern = / ( [ a - z A - Z a - z A - Z ] ) / ;
10
11
/**
@@ -21,21 +22,59 @@ const matchUnnaturalAlphabet = (text) => {
21
22
return matchCaptureGroupAll ( text , unnaturalPattern ) ;
22
23
} ;
23
24
25
+ /**
26
+ * if actual is in the `exceptGroups`, return true
27
+ * @param {MatchCaptureGroup[] } exceptGroups
28
+ * @param {MatchCaptureGroup } actual
29
+ * @returns {boolean }
30
+ */
31
+ const isIgnoredRange = ( exceptGroups , actual ) => {
32
+ return exceptGroups . some ( ( { text, index } ) => {
33
+ const endIndex = index + text . length ;
34
+ return index <= actual . index && actual . index <= endIndex ;
35
+ } ) ;
36
+ } ;
37
+ /***
38
+ *
39
+ * @param {string } input
40
+ * @param {string[] } allowAlphabets
41
+ * @returns {MatchCaptureGroup[] }
42
+ */
43
+ const createIgnoreRanges = ( input , allowAlphabets ) => {
44
+ // str -> RegExp
45
+ const patterns = allowAlphabets . map ( allowWord => {
46
+ if ( ! allowWord ) {
47
+ return / ^ $ / ;
48
+ }
49
+ if ( allowWord [ 0 ] === "/" && allowWord [ allowWord . length - 1 ] === "/" ) {
50
+ const regExpString = allowWord . slice ( 1 , allowWord . length - 1 ) ;
51
+ return new RegExp ( `(${ regExpString } )` , "g" ) ;
52
+ }
53
+ const escapeString = escapeStringRegexp ( allowWord ) ;
54
+ return new RegExp ( `(${ escapeString } )` , "g" ) ;
55
+ } ) ;
56
+ return patterns . reduce ( ( total , pattern ) => {
57
+ return total . concat ( matchCaptureGroupAll ( input , pattern ) ) ;
58
+ } , [ ] ) ;
59
+ } ;
60
+
24
61
const defaultOptions = {
25
62
// 無視するアルファベット
26
63
// 例) ["X"]
27
- // デフォルトでは母音とnを除外している
28
- "allow" : [ "a" , "i" , "u" , "e" , "o" , "n" ]
64
+ // デフォルトでは母音とnと典型例を除外している
65
+ "allow" : [ "a" , "i" , "u" , "e" , "o" , "n" , "/[a-zA-Za-zA-Z]言語/" ]
29
66
} ;
30
67
const report = ( context , options = { } ) => {
31
68
const { Syntax, RuleError, report, getSource } = context ;
32
69
const allowAlphabets = options . allow || defaultOptions . allow ;
33
70
return {
34
71
[ Syntax . Str ] ( node ) {
35
72
const text = getSource ( node ) ;
36
- matchUnnaturalAlphabet ( text ) . forEach ( ( { text, index } ) => {
37
- // 無視するアルファベットであるなら無視
38
- if ( allowAlphabets . indexOf ( text ) !== - 1 ) {
73
+ const ignoreMatch = createIgnoreRanges ( text , allowAlphabets ) ;
74
+ matchUnnaturalAlphabet ( text ) . forEach ( ( actual ) => {
75
+ const { text, index } = actual ;
76
+ // 無視する単語を含んでいるなら無視
77
+ if ( isIgnoredRange ( ignoreMatch , actual ) ) {
39
78
return ;
40
79
}
41
80
report ( node , new RuleError ( `不自然なアルファベットがあります: ${ text } ` , {
0 commit comments