Skip to content

Commit 5aaf92d

Browse files
committed
feat: 絵文字検出機能を強化し、テストケースを追加
1 parent cf953e6 commit 5aaf92d

File tree

4 files changed

+128
-32
lines changed

4 files changed

+128
-32
lines changed

.github/copilot-instructions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,9 @@ test: テストケースのメッセージを実際の出力に合わせて修
8585
技術的な正確性だけでなく、ユーザーとの良好な関係を築きながら、より良い文章作成をサポートするツールとして成長していくこと。
8686

8787
AIと人間の協力により、お互いの強みを活かした自然で読みやすい日本語文章の作成を支援する。
88+
89+
## テスト
90+
91+
テストはUnit Testのみで確認を行う
92+
93+
- `textlint-tester`を使用して、ルールのテストを行う

README.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,35 @@ AIが生成した文章によく見られる記述パターンを検出し、よ
2323

2424
#### 1-2. 絵文字を使ったリストアイテム
2525

26-
🔍 **検出される例:**
26+
AIが機械的に使いがちな装飾的な絵文字の使用を検出します。
27+
検出対象は、特に「華やか」で機械的な印象を与える絵文字に限定されています。
28+
29+
🔍 **検出される例:**
2730
```markdown
2831
- ✅ 完了した項目
29-
- ❌ 失敗した項目
32+
- ❌ 失敗した項目
3033
- 💡 アイデア項目
3134
- 🔥 ホットな話題
35+
- 🚀 開始準備完了
36+
- ⭐ 重要項目
37+
- 🎯 目標設定
38+
- 📝 メモ項目
3239
```
3340

34-
**推奨される表現:**
41+
**推奨される表現:**
3542
```markdown
3643
- 完了した項目
3744
- 失敗した項目
3845
- アイデア項目
3946
- 注目の話題
47+
- 開始準備完了
48+
- 重要項目
49+
- 目標設定
50+
- メモ項目
4051
```
4152

53+
ℹ️ **注意**: 普通の絵文字(😀, 🍎, 🐱, 🌸など)は検出されません。
54+
4255
### 2. no-ai-formal-expressions
4356
定型的で機械的な印象を与える可能性のある表現を検出します。
4457

src/rules/no-ai-list-formatting.ts

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,55 @@ const rule: TextlintRuleModule<Options> = (context, options = {}) => {
1616
const disableBoldListItems = options.disableBoldListItems ?? false;
1717
const disableEmojiListItems = options.disableEmojiListItems ?? false;
1818

19-
// AI-like emoji patterns commonly used in lists
20-
const emojiPatterns = [
19+
// Pattern to detect "flashy" emojis commonly used in AI-generated content
20+
// Using explicit list of decorative emojis that give mechanical impression
21+
const flashyEmojis = [
22+
// Check marks and status indicators
2123
"✅",
2224
"❌",
2325
"⭐",
24-
"💡",
26+
"✨",
27+
"💯",
28+
// Warning and attention symbols
29+
"⚠️",
30+
"❗",
31+
"❓",
32+
"💥",
33+
// Energy and fire symbols
2534
"🔥",
26-
"📝",
2735
"⚡",
28-
"🎯",
36+
"💪",
2937
"🚀",
30-
"🎉",
31-
"📌",
32-
"🔍",
33-
"💰",
38+
// Ideas and thinking
39+
"💡",
40+
"🤔",
41+
"💭",
42+
"🧠",
43+
// Targets and goals
44+
"🎯",
45+
"📈",
3446
"📊",
35-
"🔧",
36-
"⚠️",
37-
"❗",
38-
"💻",
39-
"📱",
40-
"🌟"
47+
"🏆",
48+
// Common decorative symbols
49+
"👍",
50+
"👎",
51+
"😊",
52+
"😎",
53+
"🎉",
54+
"🌟",
55+
// Work and productivity
56+
"📝",
57+
"📋",
58+
"✏️",
59+
"🖊️",
60+
"💼"
4161
];
4262

63+
// Create pattern from explicit emoji list
64+
// Need to escape special regex characters
65+
const escapedEmojis = flashyEmojis.map((emoji) => emoji.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
66+
const flashyEmojiPattern = new RegExp(`(${escapedEmojis.join("|")})`);
67+
4368
return {
4469
[Syntax.ListItem](node) {
4570
const text = getSource(node);
@@ -72,19 +97,18 @@ const rule: TextlintRuleModule<Options> = (context, options = {}) => {
7297

7398
// Check for emoji list items
7499
if (!disableEmojiListItems) {
75-
for (const emoji of emojiPatterns) {
76-
const emojiIndex = text.indexOf(emoji);
77-
if (emojiIndex !== -1) {
78-
const matchRange = [emojiIndex, emojiIndex + emoji.length] as const;
79-
const ruleError = new RuleError(
80-
`リストアイテムでの絵文字「${emoji}」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。`,
81-
{
82-
padding: locator.range(matchRange)
83-
}
84-
);
85-
report(node, ruleError);
86-
break; // Only report the first emoji found in each list item
87-
}
100+
const emojiMatch = text.match(flashyEmojiPattern);
101+
if (emojiMatch) {
102+
const emoji = emojiMatch[0];
103+
const emojiIndex = emojiMatch.index ?? 0;
104+
const matchRange = [emojiIndex, emojiIndex + emoji.length] as const;
105+
const ruleError = new RuleError(
106+
`リストアイテムでの絵文字「${emoji}」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。`,
107+
{
108+
padding: locator.range(matchRange)
109+
}
110+
);
111+
report(node, ruleError);
88112
}
89113
}
90114
}

test/rules/no-ai-list-formatting.test.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,19 @@ tester.run("no-ai-list-formatting", noAiListFormatting, {
4444
options: {
4545
disableEmojiListItems: true
4646
}
47-
}
47+
},
48+
// Non-flashy emojis that should NOT be detected
49+
"- 😀 普通の笑顔",
50+
"- 🍎 りんご",
51+
"- 🐱 猫",
52+
"- 🌸 桜",
53+
"- ❤️ ハート",
54+
// Non-flashy emojis that should NOT be detected
55+
"- 😀 普通の笑顔",
56+
"- 🍎 りんご",
57+
"- 🐱 猫",
58+
"- 🌸 桜",
59+
"- ❤️ ハート"
4860
],
4961
invalid: [
5062
// Bold list item pattern
@@ -122,6 +134,47 @@ tester.run("no-ai-list-formatting", noAiListFormatting, {
122134
range: [18, 20]
123135
}
124136
]
137+
},
138+
// Additional flashy emoji tests
139+
{
140+
text: "- 🚀 ロケット項目",
141+
errors: [
142+
{
143+
message:
144+
"リストアイテムでの絵文字「🚀」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。",
145+
range: [2, 4]
146+
}
147+
]
148+
},
149+
{
150+
text: "- ⭐ 星印項目",
151+
errors: [
152+
{
153+
message:
154+
"リストアイテムでの絵文字「⭐」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。",
155+
range: [2, 3]
156+
}
157+
]
158+
},
159+
{
160+
text: "- 🎯 ターゲット項目",
161+
errors: [
162+
{
163+
message:
164+
"リストアイテムでの絵文字「🎯」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。",
165+
range: [2, 4]
166+
}
167+
]
168+
},
169+
{
170+
text: "- 📝 メモ項目",
171+
errors: [
172+
{
173+
message:
174+
"リストアイテムでの絵文字「📝」の使用は、読み手によっては機械的な印象を与える場合があります。テキストベースの表現も検討してみてください。",
175+
range: [2, 4]
176+
}
177+
]
125178
}
126179
]
127180
});

0 commit comments

Comments
 (0)