nodebb-plugin-mentions 4.0.6 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/library.js CHANGED
@@ -27,7 +27,12 @@ const SocketPlugins = require.main.require('./src/socket.io/plugins');
27
27
 
28
28
  const utility = require('./lib/utility');
29
29
 
30
- const regex = XRegExp('(?:^|\\s|\\>|;)(@[\\p{L}\\d\\-_.]+)', 'g');
30
+ const parts = {
31
+ before: '(?:(^|\\p{^L}))', // a single unicode non-letter character or start of line
32
+ main: '(@[\\p{L}\\d\\-_.]+)', // unicode letters, numbers, dashes, underscores, or periods
33
+ after: '((?=\\b)(?=[^-])|$)', // used to figure out where latin mentions end
34
+ };
35
+ const regex = XRegExp(`${parts.before}${parts.main}`, 'g');
31
36
  const isLatinMention = /@[\w\d\-_.]+$/;
32
37
 
33
38
  const Mentions = module.exports;
@@ -293,8 +298,8 @@ Mentions.parseRaw = async (content) => {
293
298
 
294
299
  if (results.user.uid || results.groupExists) {
295
300
  const regex = isLatinMention.test(match) ?
296
- new RegExp(`(?:^|\\s|>|;)${match}((?=\\b)(?=[^-])|$)`, 'g') :
297
- new RegExp(`(?:^|\\s|>|;)${match}`, 'g');
301
+ XRegExp(`${parts.before}${match}${parts.after}`, 'g') :
302
+ XRegExp(`${parts.before}${match}`, 'g');
298
303
 
299
304
  let skip = false;
300
305
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-mentions",
3
- "version": "4.0.6",
3
+ "version": "4.1.0",
4
4
  "description": "NodeBB Plugin that allows users to mention other users by prepending an '@' sign to their username",
5
5
  "main": "library.js",
6
6
  "scripts": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "mocha": "10.2.0",
35
- "eslint": "8.37.0",
35
+ "eslint": "8.39.0",
36
36
  "eslint-config-nodebb": "0.2.1",
37
37
  "eslint-plugin-import": "2.27.5"
38
38
  }
package/test/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- /* globals describe, it, before */
3
+ /* globals describe, it, beforeEach */
4
4
 
5
5
  const assert = require('assert');
6
6
 
@@ -16,23 +16,28 @@ const regex = main._regex;
16
16
  // use core slugify module
17
17
  const slugify = require.main.require('./src/slugify');
18
18
 
19
+ const strings = [
20
+ '@testUser',
21
+ '@testUser some text',
22
+ 'some text @testUser',
23
+ '<a href="/user/testuser">@testUser</a>',
24
+ '<a href="/user/testuser">@testUser</a> some text',
25
+ 'some text <a href="/user/testuser">@testUser</a>',
26
+ 'end of sentence. @testUser',
27
+ '@testUser.',
28
+ '@testUser\'s some text',
29
+ '> @testUser blockquoted',
30
+ '(@testUser) bracketed',
31
+ 'elon makes me think of this emoji: 💩@testUser',
32
+ ];
33
+
19
34
  describe('regex', () => {
20
35
  const matcher = new RegExp(regex);
21
- const strings = [
22
- '@testUser',
23
- '@testUser some text',
24
- 'some text @testUser',
25
- '<a href="/user/testuser">@testUser</a>',
26
- '<a href="/user/testuser">@testUser</a> some text',
27
- 'some text <a href="/user/testuser">@testUser</a>',
28
- 'end of sentence. @testUser',
29
- '@testUser.',
30
- '@testUser\'s some text',
31
- ];
32
- it('should match a mention in all strings', () => {
33
- strings.forEach((string) => {
36
+
37
+ strings.forEach((string) => {
38
+ it('should match a mention in all test strings', () => {
34
39
  const matches = string.match(matcher);
35
- assert(matches);
40
+ assert(matches, `@testUser was not found in this string: ${string}`);
36
41
  assert.equal(slugify(matches[0]), 'testuser');
37
42
  });
38
43
  });
@@ -152,19 +157,35 @@ describe('splitter', () => {
152
157
 
153
158
  describe('parser', () => {
154
159
  let slug;
160
+ let uid;
155
161
 
156
- before(async () => {
162
+ beforeEach(async () => {
157
163
  slug = utils.generateUUID().slice(0, 10);
158
- await Promise.all([slug, `${slug}-two`].map(async (username) => {
159
- await user.create({ username });
160
- }));
164
+ uid = await user.create({ username: slug });
161
165
  });
162
166
 
163
167
  it('should properly parse both users even if one user\'s username is a subset of the other', async () => {
168
+ await user.create({ username: `${slug}-two` });
164
169
  const md = `This sentence contains two mentions: @${slug} and @${slug}-two`;
165
170
 
166
171
  const html = await main.parseRaw(md);
167
172
 
168
173
  assert.strictEqual(html, `This sentence contains two mentions: <a class="plugin-mentions-user plugin-mentions-a" href="http://127.0.0.1:4567/uid/1">@${slug}</a> and <a class="plugin-mentions-user plugin-mentions-a" href="http://127.0.0.1:4567/uid/2">@${slug}-two</a>`);
169
174
  });
175
+
176
+ strings.forEach((string) => {
177
+ it('should match correctly replace the mentions in all test strings', async () => {
178
+ const index = string.indexOf('@testUser');
179
+ let check = string;
180
+ if (!index || string[index - 1] !== '>') {
181
+ check = string.replace(/@testUser/g, `<a class="plugin-mentions-user plugin-mentions-a" href="http://127.0.0.1:4567/uid/${uid}">@${slug}</a>`);
182
+ string = string.replace(/testUser/g, slug);
183
+ }
184
+ const html = await main.parseRaw(string);
185
+
186
+ assert(html);
187
+
188
+ assert.strictEqual(html, check);
189
+ });
190
+ });
170
191
  });