From e4b161a44638d6b47124f2a3c0ac0871a90242f1 Mon Sep 17 00:00:00 2001 From: yuiseki Date: Fri, 25 Oct 2024 22:44:25 +0900 Subject: [PATCH] =?UTF-8?q?Fix=20hashtag=20plugin:=20add=20support=20for?= =?UTF-8?q?=20full=20width=20middle=20dot=20`=E3=83=BB`=20(#492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/linkify-plugin-hashtag/src/hashtag.js | 7 +++++-- packages/linkifyjs/src/scanner.js | 1 + packages/linkifyjs/src/text.js | 1 + test/spec/linkify-plugin-hashtag.test.js | 8 ++++++++ test/spec/linkifyjs/scanner.test.js | 6 ++++++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/linkify-plugin-hashtag/src/hashtag.js b/packages/linkify-plugin-hashtag/src/hashtag.js index d136e0c..491c058 100644 --- a/packages/linkify-plugin-hashtag/src/hashtag.js +++ b/packages/linkify-plugin-hashtag/src/hashtag.js @@ -6,9 +6,9 @@ const HashtagToken = createTokenClass('hashtag', { isLink: true }); /** * @type {import('linkifyjs').Plugin} */ - export default function hashtag({ scanner, parser }) { +export default function hashtag({ scanner, parser }) { // Various tokens that may compose a hashtag - const { POUND, UNDERSCORE } = scanner.tokens; + const { POUND, UNDERSCORE, FULLWIDTHMIDDLEDOT } = scanner.tokens; const { alpha, numeric, alphanumeric, emoji } = scanner.tokens.groups; // Take or create a transition from start to the '#' sign (non-accepting) @@ -21,11 +21,14 @@ const HashtagToken = createTokenClass('hashtag', { isLink: true }); Hash.ta(numeric, HashPrefix); Hash.ta(alpha, Hashtag); Hash.ta(emoji, Hashtag); + Hash.ta(FULLWIDTHMIDDLEDOT, Hashtag); HashPrefix.ta(alpha, Hashtag); HashPrefix.ta(emoji, Hashtag); + HashPrefix.ta(FULLWIDTHMIDDLEDOT, Hashtag); HashPrefix.ta(numeric, HashPrefix); HashPrefix.tt(UNDERSCORE, HashPrefix); Hashtag.ta(alphanumeric, Hashtag); Hashtag.ta(emoji, Hashtag); + Hashtag.tt(FULLWIDTHMIDDLEDOT, Hashtag); Hashtag.tt(UNDERSCORE, Hashtag); // Trailing underscore is okay } diff --git a/packages/linkifyjs/src/scanner.js b/packages/linkifyjs/src/scanner.js index 7de6787..325964c 100644 --- a/packages/linkifyjs/src/scanner.js +++ b/packages/linkifyjs/src/scanner.js @@ -94,6 +94,7 @@ export function init(customSchemes = []) { tt(Start, '~', tk.TILDE); tt(Start, '_', tk.UNDERSCORE); tt(Start, '\\', tk.BACKSLASH); + tt(Start, '・', tk.FULLWIDTHMIDDLEDOT); const Num = tr(Start, re.DIGIT, tk.NUM, { [fsm.numeric]: true }); tr(Num, re.DIGIT, Num); diff --git a/packages/linkifyjs/src/text.js b/packages/linkifyjs/src/text.js index 5b0feb1..3a44c36 100644 --- a/packages/linkifyjs/src/text.js +++ b/packages/linkifyjs/src/text.js @@ -76,6 +76,7 @@ export const PLUS = 'PLUS'; // + export const POUND = 'POUND'; // # export const QUERY = 'QUERY'; // ? export const QUOTE = 'QUOTE'; // " +export const FULLWIDTHMIDDLEDOT = 'FULLWIDTHMIDDLEDOT'; // ・ export const SEMI = 'SEMI'; // ; export const SLASH = 'SLASH'; // / diff --git a/test/spec/linkify-plugin-hashtag.test.js b/test/spec/linkify-plugin-hashtag.test.js index f834ba5..8cada9e 100644 --- a/test/spec/linkify-plugin-hashtag.test.js +++ b/test/spec/linkify-plugin-hashtag.test.js @@ -80,6 +80,14 @@ describe('linkify-plugin-hashtag', () => { expect(linkify.test('#سلام', 'hashtag')).to.be.ok; }); + it('Works with Japanese characters', () => { + expect(linkify.test('#おはよう', 'hashtag')).to.be.ok; + }); + + it('Works with Japanese characters and full width middle dot', () => { + expect(linkify.test('#おは・よう', 'hashtag')).to.be.ok; + }); + it('Works with emojis', () => { expect(linkify.test('#🍭', 'hashtag')).to.be.ok; }); diff --git a/test/spec/linkifyjs/scanner.test.js b/test/spec/linkifyjs/scanner.test.js index f7c9574..e01c00a 100644 --- a/test/spec/linkifyjs/scanner.test.js +++ b/test/spec/linkifyjs/scanner.test.js @@ -27,6 +27,7 @@ const tests = [ ['$', [t.DOLLAR], ['$']], ['=', [t.EQUALS], ['=']], ['-', [t.HYPHEN], ['-']], + ['・', [t.FULLWIDTHMIDDLEDOT], ['・']], ['&?<>(', [t.AMPERSAND, t.QUERY, t.OPENANGLEBRACKET, t.CLOSEANGLEBRACKET, t.OPENPAREN], ['&', '?', '<', '>', '(']], ['([{}])', [t.OPENPAREN, t.OPENBRACKET, t.OPENBRACE, t.CLOSEBRACE, t.CLOSEBRACKET, t.CLOSEPAREN], ['(', '[', '{', '}', ']', ')']], ['!,;\'', [t.EXCLAMATION, t.COMMA, t.SEMI, t.APOSTROPHE], ['!', ',', ';', '\'']], @@ -83,6 +84,11 @@ const tests = [ [t.POUND, t.UWORD, t.UNDERSCORE, t.UWORD, t.WS, t.POUND, t.UWORD, t.WS, t.POUND, t.UWORD], ['#', 'АБВ', '_', 'бв', ' ', '#', '한글', ' ', '#', 'سلام'] ], + [ + '#おは・よう', + [t.POUND, t.UWORD, t.FULLWIDTHMIDDLEDOT, t.UWORD], + ['#', 'おは', '・', 'よう'] + ], [ 'テストexample.comテスト', [t.UWORD, t.WORD, t.DOT, t.TLD, t.UWORD],