mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 12:45:11 +08:00
Upgrade linkify to v3.0 (#7282)
Co-authored-by: Timo K <toger5@hotmail.de>
This commit is contained in:
parent
c0681333bf
commit
336e1ae3b6
@ -85,7 +85,9 @@
|
|||||||
"is-ip": "^3.1.0",
|
"is-ip": "^3.1.0",
|
||||||
"jszip": "^3.7.0",
|
"jszip": "^3.7.0",
|
||||||
"katex": "^0.12.0",
|
"katex": "^0.12.0",
|
||||||
"linkifyjs": "^2.1.9",
|
"linkify-element": "^3.0.4",
|
||||||
|
"linkify-string": "^3.0.4",
|
||||||
|
"linkifyjs": "^3.0.5",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"maplibre-gl": "^1.15.2",
|
"maplibre-gl": "^1.15.2",
|
||||||
"matrix-analytics-events": "https://github.com/matrix-org/matrix-analytics-events.git#1eab4356548c97722a183912fda1ceabbe8cc7c1",
|
"matrix-analytics-events": "https://github.com/matrix-org/matrix-analytics-events.git#1eab4356548c97722a183912fda1ceabbe8cc7c1",
|
||||||
|
@ -16,9 +16,10 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as linkifyjs from 'linkifyjs';
|
import * as linkifyjs from 'linkifyjs';
|
||||||
import linkifyElement from 'linkifyjs/element';
|
import linkifyElement from 'linkify-element';
|
||||||
import linkifyString from 'linkifyjs/string';
|
import linkifyString from 'linkify-string';
|
||||||
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
||||||
|
import { registerPlugin } from 'linkifyjs';
|
||||||
|
|
||||||
import { baseUrl } from "./utils/permalinks/SpecPermalinkConstructor";
|
import { baseUrl } from "./utils/permalinks/SpecPermalinkConstructor";
|
||||||
import {
|
import {
|
||||||
@ -37,73 +38,82 @@ enum Type {
|
|||||||
GroupId = "groupid"
|
GroupId = "groupid"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linkifyjs types don't have parser, which really makes this harder.
|
// Linkify stuff doesn't type scanner/parser/utils properly :/
|
||||||
const linkifyTokens = (linkifyjs as any).scanner.TOKENS;
|
function matrixOpaqueIdLinkifyParser({
|
||||||
enum MatrixLinkInitialToken {
|
scanner,
|
||||||
POUND = linkifyTokens.POUND,
|
parser,
|
||||||
PLUS = linkifyTokens.PLUS,
|
utils,
|
||||||
AT = linkifyTokens.AT,
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Token should be one of the type of linkify.parser.TOKENS[AT | PLUS | POUND]
|
|
||||||
* but due to typing issues it's just not a feasible solution.
|
|
||||||
* This problem kind of gets solved in linkify 3.0
|
|
||||||
*/
|
|
||||||
function parseFreeformMatrixLinks(linkify, token: MatrixLinkInitialToken, type: Type): void {
|
|
||||||
// Text tokens
|
|
||||||
const TT = linkify.scanner.TOKENS;
|
|
||||||
// Multi tokens
|
|
||||||
const MT = linkify.parser.TOKENS;
|
|
||||||
const MultiToken = MT.Base;
|
|
||||||
const S_START = linkify.parser.start;
|
|
||||||
|
|
||||||
const TOKEN = function(value) {
|
|
||||||
MultiToken.call(this, value);
|
|
||||||
this.type = type;
|
|
||||||
this.isLink = true;
|
|
||||||
};
|
|
||||||
TOKEN.prototype = new MultiToken();
|
|
||||||
|
|
||||||
const S_TOKEN = S_START.jump(token);
|
|
||||||
const S_TOKEN_NAME = new linkify.parser.State();
|
|
||||||
const S_TOKEN_NAME_COLON = new linkify.parser.State();
|
|
||||||
const S_TOKEN_NAME_COLON_DOMAIN = new linkify.parser.State(TOKEN);
|
|
||||||
const S_TOKEN_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
|
|
||||||
const S_MX_LINK = new linkify.parser.State(TOKEN);
|
|
||||||
const S_MX_LINK_COLON = new linkify.parser.State();
|
|
||||||
const S_MX_LINK_COLON_NUM = new linkify.parser.State(TOKEN);
|
|
||||||
|
|
||||||
const allowedFreeformTokens = [
|
|
||||||
TT.DOT,
|
|
||||||
TT.PLUS,
|
|
||||||
TT.NUM,
|
|
||||||
TT.DOMAIN,
|
|
||||||
TT.TLD,
|
|
||||||
TT.UNDERSCORE,
|
|
||||||
token,
|
token,
|
||||||
|
name,
|
||||||
|
}: {
|
||||||
|
scanner: any;
|
||||||
|
parser: any;
|
||||||
|
utils: any;
|
||||||
|
token: '#' | '+' | '@';
|
||||||
|
name: Type;
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
DOMAIN,
|
||||||
|
DOT,
|
||||||
|
// A generic catchall text token
|
||||||
|
TEXT,
|
||||||
|
NUM,
|
||||||
|
TLD,
|
||||||
|
COLON,
|
||||||
|
SYM,
|
||||||
|
UNDERSCORE,
|
||||||
|
// because 'localhost' is tokenised to the localhost token,
|
||||||
|
// usernames @localhost:foo.com are otherwise not matched!
|
||||||
|
LOCALHOST,
|
||||||
|
} = scanner.tokens;
|
||||||
|
|
||||||
|
const S_START = parser.start;
|
||||||
|
const matrixSymbol = utils.createTokenClass(name, { isLink: true });
|
||||||
|
|
||||||
|
const localpartTokens = [
|
||||||
|
DOMAIN,
|
||||||
|
// IPV4 necessity
|
||||||
|
NUM,
|
||||||
|
TLD,
|
||||||
|
|
||||||
// because 'localhost' is tokenised to the localhost token,
|
// because 'localhost' is tokenised to the localhost token,
|
||||||
// usernames @localhost:foo.com are otherwise not matched!
|
// usernames @localhost:foo.com are otherwise not matched!
|
||||||
TT.LOCALHOST,
|
LOCALHOST,
|
||||||
|
SYM,
|
||||||
|
UNDERSCORE,
|
||||||
|
TEXT,
|
||||||
];
|
];
|
||||||
|
const domainpartTokens = [DOMAIN, NUM, TLD, LOCALHOST];
|
||||||
|
|
||||||
S_TOKEN.on(allowedFreeformTokens, S_TOKEN_NAME);
|
const INITIAL_STATE = S_START.tt(token);
|
||||||
S_TOKEN_NAME.on(allowedFreeformTokens, S_TOKEN_NAME);
|
|
||||||
S_TOKEN_NAME.on(TT.DOMAIN, S_TOKEN_NAME);
|
|
||||||
|
|
||||||
S_TOKEN_NAME.on(TT.COLON, S_TOKEN_NAME_COLON);
|
const LOCALPART_STATE = INITIAL_STATE.tt(DOMAIN);
|
||||||
|
for (const token of localpartTokens) {
|
||||||
|
INITIAL_STATE.tt(token, LOCALPART_STATE);
|
||||||
|
LOCALPART_STATE.tt(token, LOCALPART_STATE);
|
||||||
|
}
|
||||||
|
const LOCALPART_STATE_DOT = LOCALPART_STATE.tt(DOT);
|
||||||
|
for (const token of localpartTokens) {
|
||||||
|
LOCALPART_STATE_DOT.tt(token, LOCALPART_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
S_TOKEN_NAME_COLON.on(TT.DOMAIN, S_TOKEN_NAME_COLON_DOMAIN);
|
const DOMAINPART_STATE_DOT = LOCALPART_STATE.tt(COLON);
|
||||||
S_TOKEN_NAME_COLON.on(TT.LOCALHOST, S_MX_LINK); // accept #foo:localhost
|
const DOMAINPART_STATE = DOMAINPART_STATE_DOT.tt(DOMAIN);
|
||||||
S_TOKEN_NAME_COLON.on(TT.TLD, S_MX_LINK); // accept #foo:com (mostly for (TLD|DOMAIN)+ mixing)
|
DOMAINPART_STATE.tt(DOT, DOMAINPART_STATE_DOT);
|
||||||
S_TOKEN_NAME_COLON_DOMAIN.on(TT.DOT, S_TOKEN_NAME_COLON_DOMAIN_DOT);
|
for (const token of domainpartTokens) {
|
||||||
S_TOKEN_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_TOKEN_NAME_COLON_DOMAIN);
|
DOMAINPART_STATE.tt(token, DOMAINPART_STATE);
|
||||||
S_TOKEN_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_MX_LINK);
|
// we are done if we have a domain
|
||||||
|
DOMAINPART_STATE.tt(token, matrixSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
S_MX_LINK.on(TT.DOT, S_TOKEN_NAME_COLON_DOMAIN_DOT); // accept repeated TLDs (e.g .org.uk)
|
// accept repeated TLDs (e.g .org.uk) but do not accept double dots: ..
|
||||||
S_MX_LINK.on(TT.COLON, S_MX_LINK_COLON); // do not accept trailing `:`
|
for (const token of domainpartTokens) {
|
||||||
S_MX_LINK_COLON.on(TT.NUM, S_MX_LINK_COLON_NUM); // but do accept :NUM (port specifier)
|
DOMAINPART_STATE_DOT.tt(token, DOMAINPART_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PORT_STATE = DOMAINPART_STATE.tt(COLON);
|
||||||
|
|
||||||
|
PORT_STATE.tt(NUM, matrixSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUserClick(event: MouseEvent, userId: string) {
|
function onUserClick(event: MouseEvent, userId: string) {
|
||||||
@ -199,10 +209,12 @@ export const options = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
linkAttributes: {
|
attributes: {
|
||||||
rel: 'noreferrer noopener',
|
rel: 'noreferrer noopener',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
className: 'linkified',
|
||||||
|
|
||||||
target: function(href: string, type: Type | string): string {
|
target: function(href: string, type: Type | string): string {
|
||||||
if (type === Type.URL) {
|
if (type === Type.URL) {
|
||||||
try {
|
try {
|
||||||
@ -221,12 +233,38 @@ export const options = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Run the plugins
|
// Run the plugins
|
||||||
// Linkify room aliases
|
registerPlugin(Type.RoomAlias, ({ scanner, parser, utils }) => {
|
||||||
parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.POUND, Type.RoomAlias);
|
const token = scanner.tokens.POUND as '#';
|
||||||
// Linkify group IDs
|
return matrixOpaqueIdLinkifyParser({
|
||||||
parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.PLUS, Type.GroupId);
|
scanner,
|
||||||
// Linkify user IDs
|
parser,
|
||||||
parseFreeformMatrixLinks(linkifyjs, MatrixLinkInitialToken.AT, Type.UserId);
|
utils,
|
||||||
|
token,
|
||||||
|
name: Type.RoomAlias,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
registerPlugin(Type.GroupId, ({ scanner, parser, utils }) => {
|
||||||
|
const token = scanner.tokens.PLUS as '+';
|
||||||
|
return matrixOpaqueIdLinkifyParser({
|
||||||
|
scanner,
|
||||||
|
parser,
|
||||||
|
utils,
|
||||||
|
token,
|
||||||
|
name: Type.GroupId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
registerPlugin(Type.UserId, ({ scanner, parser, utils }) => {
|
||||||
|
const token = scanner.tokens.AT as '@';
|
||||||
|
return matrixOpaqueIdLinkifyParser({
|
||||||
|
scanner,
|
||||||
|
parser,
|
||||||
|
utils,
|
||||||
|
token,
|
||||||
|
name: Type.UserId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
export const linkify = linkifyjs;
|
export const linkify = linkifyjs;
|
||||||
export const _linkifyElement = linkifyElement;
|
export const _linkifyElement = linkifyElement;
|
||||||
|
@ -16,215 +16,252 @@ limitations under the License.
|
|||||||
import { linkify } from '../src/linkify-matrix';
|
import { linkify } from '../src/linkify-matrix';
|
||||||
|
|
||||||
describe('linkify-matrix', () => {
|
describe('linkify-matrix', () => {
|
||||||
describe('roomalias', () => {
|
const linkTypesByInitialCharacter = {
|
||||||
it('properly parses #_foonetic_xkcd:matrix.org', () => {
|
'#': 'roomalias',
|
||||||
const test = '#_foonetic_xkcd:matrix.org';
|
'@': 'userid',
|
||||||
|
'+': 'groupid',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param testName Due to all the tests using the same logic underneath, it makes to generate it in a bit smarter way
|
||||||
|
* @param char
|
||||||
|
*/
|
||||||
|
function genTests(char: '#' | '@' | '+') {
|
||||||
|
const type = linkTypesByInitialCharacter[char];
|
||||||
|
it('should not parse ' + char + 'foo without domain', () => {
|
||||||
|
const test = char + "foo";
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual(([]));
|
||||||
|
});
|
||||||
|
describe('ip v4 tests', () => {
|
||||||
|
it('should properly parse IPs v4 as the domain name', () => {
|
||||||
|
const test = char + 'potato:1.2.3.4';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#_foonetic_xkcd:matrix.org",
|
href: char + 'potato:1.2.3.4',
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#_foonetic_xkcd:matrix.org",
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
value: char + 'potato:1.2.3.4',
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('properly parses #foo:localhost', () => {
|
it('should properly parse IPs v4 with port as the domain name with attached', () => {
|
||||||
const test = "#foo:localhost";
|
const test = char + 'potato:1.2.3.4:1337';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:localhost",
|
href: char + 'potato:1.2.3.4:1337',
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:localhost",
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
value: char + 'potato:1.2.3.4:1337',
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('accept #foo:bar.com', () => {
|
it('should properly parse IPs v4 as the domain name while ignoring missing port', () => {
|
||||||
const test = '#foo:bar.com';
|
const test = char + 'potato:1.2.3.4:';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:bar.com",
|
href: char + 'potato:1.2.3.4',
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:bar.com",
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length - 1,
|
||||||
|
value: char + 'potato:1.2.3.4',
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('accept #foo:com (mostly for (TLD|DOMAIN)+ mixing)', () => {
|
});
|
||||||
const test = '#foo:com';
|
// Currently those tests are failing, as there's missing implementation.
|
||||||
|
describe.skip('ip v6 tests', () => {
|
||||||
|
it('should properly parse IPs v6 as the domain name', () => {
|
||||||
|
const test = char + "username:[1234:5678::abcd]";
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual([{
|
||||||
|
href: char + 'username:[1234:5678::abcd]',
|
||||||
|
type,
|
||||||
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
value: char + 'username:[1234:5678::abcd]',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should properly parse IPs v6 with port as the domain name', () => {
|
||||||
|
const test = char + "username:[1234:5678::abcd]:1337";
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual([{
|
||||||
|
href: char + 'username:[1234:5678::abcd]:1337',
|
||||||
|
type,
|
||||||
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
value: char + 'username:[1234:5678::abcd]:1337',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
it('should properly parse IPs v6 while ignoring dangling comma when without port name as the domain name', () => {
|
||||||
|
const test = char + "username:[1234:5678::abcd]:";
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual([{
|
||||||
|
href: char + 'username:[1234:5678::abcd]:',
|
||||||
|
type,
|
||||||
|
isLink: true,
|
||||||
|
start: 0,
|
||||||
|
end: test.length - 1,
|
||||||
|
value: char + 'username:[1234:5678::abcd]:',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('properly parses ' + char + '_foonetic_xkcd:matrix.org', () => {
|
||||||
|
const test = '' + char + '_foonetic_xkcd:matrix.org';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:com",
|
href: char + "_foonetic_xkcd:matrix.org",
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:com",
|
value: char + "_foonetic_xkcd:matrix.org",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
isLink: true,
|
||||||
|
}]));
|
||||||
|
});
|
||||||
|
it('properly parses ' + char + 'foo:localhost', () => {
|
||||||
|
const test = char + "foo:localhost";
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual(([{
|
||||||
|
href: char + "foo:localhost",
|
||||||
|
type,
|
||||||
|
value: char + "foo:localhost",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
isLink: true,
|
||||||
|
}]));
|
||||||
|
});
|
||||||
|
it('accept ' + char + 'foo:bar.com', () => {
|
||||||
|
const test = '' + char + 'foo:bar.com';
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual(([{
|
||||||
|
href: char + "foo:bar.com",
|
||||||
|
type,
|
||||||
|
value: char + "foo:bar.com",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
|
||||||
|
isLink: true,
|
||||||
|
}]));
|
||||||
|
});
|
||||||
|
it('accept ' + char + 'foo:com (mostly for (TLD|DOMAIN)+ mixing)', () => {
|
||||||
|
const test = '' + char + 'foo:com';
|
||||||
|
const found = linkify.find(test);
|
||||||
|
expect(found).toEqual(([{
|
||||||
|
href: char + "foo:com",
|
||||||
|
type,
|
||||||
|
value: char + "foo:com",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('accept repeated TLDs (e.g .org.uk)', () => {
|
it('accept repeated TLDs (e.g .org.uk)', () => {
|
||||||
const test = '#foo:bar.org.uk';
|
const test = '' + char + 'foo:bar.org.uk';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:bar.org.uk",
|
href: char + "foo:bar.org.uk",
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:bar.org.uk",
|
value: char + "foo:bar.org.uk",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('ignores trailing `:`', () => {
|
it('ignores trailing `:`', () => {
|
||||||
const test = '#foo:bar.com:';
|
const test = '' + char + 'foo:bar.com:';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:bar.com",
|
type,
|
||||||
type: "roomalias",
|
value: char + "foo:bar.com",
|
||||||
value: "#foo:bar.com",
|
href: char + 'foo:bar.com',
|
||||||
|
start: 0,
|
||||||
|
end: test.length - ":".length,
|
||||||
|
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('accept :NUM (port specifier)', () => {
|
it('accept :NUM (port specifier)', () => {
|
||||||
const test = '#foo:bar.com:2225';
|
const test = '' + char + 'foo:bar.com:2225';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:bar.com:2225",
|
href: char + "foo:bar.com:2225",
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:bar.com:2225",
|
value: char + "foo:bar.com:2225",
|
||||||
|
start: 0,
|
||||||
|
end: test.length,
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('ignores all the trailing :', () => {
|
it('ignores all the trailing :', () => {
|
||||||
const test = '#foo:bar.com::::';
|
const test = '' + char + 'foo:bar.com::::';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo:bar.com",
|
href: char + "foo:bar.com",
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo:bar.com",
|
value: char + "foo:bar.com",
|
||||||
|
end: test.length - 4,
|
||||||
|
start: 0,
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('properly parses room alias with dots in name', () => {
|
it('properly parses room alias with dots in name', () => {
|
||||||
const test = '#foo.asdf:bar.com::::';
|
const test = '' + char + 'foo.asdf:bar.com::::';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "#foo.asdf:bar.com",
|
href: char + "foo.asdf:bar.com",
|
||||||
type: "roomalias",
|
type,
|
||||||
value: "#foo.asdf:bar.com",
|
value: char + "foo.asdf:bar.com",
|
||||||
|
start: 0,
|
||||||
|
end: test.length - ":".repeat(4).length,
|
||||||
|
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('does not parse room alias with too many separators', () => {
|
it('does not parse room alias with too many separators', () => {
|
||||||
const test = '#foo:::bar.com';
|
const test = '' + char + 'foo:::bar.com';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
href: "http://bar.com",
|
href: "http://bar.com",
|
||||||
type: "url",
|
type: "url",
|
||||||
value: "bar.com",
|
value: "bar.com",
|
||||||
|
isLink: true,
|
||||||
|
start: 7,
|
||||||
|
end: test.length,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
it('does not parse multiple room aliases in one string', () => {
|
it('does not parse multiple room aliases in one string', () => {
|
||||||
const test = '#foo:bar.com-baz.com';
|
const test = '' + char + 'foo:bar.com-baz.com';
|
||||||
const found = linkify.find(test);
|
const found = linkify.find(test);
|
||||||
expect(found).toEqual(([{
|
expect(found).toEqual(([{
|
||||||
"href": "#foo:bar.com-baz.com",
|
href: char + "foo:bar.com-baz.com",
|
||||||
"type": "roomalias",
|
type,
|
||||||
"value": "#foo:bar.com-baz.com",
|
value: char + "foo:bar.com-baz.com",
|
||||||
|
end: 20,
|
||||||
|
start: 0,
|
||||||
|
isLink: true,
|
||||||
}]));
|
}]));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('roomalias plugin', () => {
|
||||||
|
genTests('#');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('groupid', () => {
|
describe('groupid plugin', () => {
|
||||||
it('properly parses +foo:localhost', () => {
|
genTests('+');
|
||||||
const test = "+foo:localhost";
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "+foo:localhost",
|
|
||||||
type: "groupid",
|
|
||||||
value: "+foo:localhost",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept +foo:bar.com', () => {
|
|
||||||
const test = '+foo:bar.com';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "+foo:bar.com",
|
|
||||||
type: "groupid",
|
|
||||||
value: "+foo:bar.com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept +foo:com (mostly for (TLD|DOMAIN)+ mixing)', () => {
|
|
||||||
const test = '+foo:com';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "+foo:com",
|
|
||||||
type: "groupid",
|
|
||||||
value: "+foo:com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept repeated TLDs (e.g .org.uk)', () => {
|
|
||||||
const test = '+foo:bar.org.uk';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "+foo:bar.org.uk",
|
|
||||||
type: "groupid",
|
|
||||||
value: "+foo:bar.org.uk",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('ignore trailing `:`', () => {
|
|
||||||
const test = '+foo:bar.com:';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
"href": "+foo:bar.com",
|
|
||||||
"type": "groupid",
|
|
||||||
"value": "+foo:bar.com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept :NUM (port specifier)', () => {
|
|
||||||
const test = '+foo:bar.com:2225';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "+foo:bar.com:2225",
|
|
||||||
type: "groupid",
|
|
||||||
value: "+foo:bar.com:2225",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('userid', () => {
|
describe('userid plugin', () => {
|
||||||
it('should not parse @foo without domain', () => {
|
genTests('@');
|
||||||
const test = "@foo";
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([]));
|
|
||||||
});
|
|
||||||
it('accept @foo:bar.com', () => {
|
|
||||||
const test = '@foo:bar.com';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "@foo:bar.com",
|
|
||||||
type: "userid",
|
|
||||||
value: "@foo:bar.com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept @foo:com (mostly for (TLD|DOMAIN)+ mixing)', () => {
|
|
||||||
const test = '@foo:com';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "@foo:com",
|
|
||||||
type: "userid",
|
|
||||||
value: "@foo:com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept repeated TLDs (e.g .org.uk)', () => {
|
|
||||||
const test = '@foo:bar.org.uk';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "@foo:bar.org.uk",
|
|
||||||
type: "userid",
|
|
||||||
value: "@foo:bar.org.uk",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('do not accept trailing `:`', () => {
|
|
||||||
const test = '@foo:bar.com:';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "@foo:bar.com",
|
|
||||||
type: "userid",
|
|
||||||
value: "@foo:bar.com",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
it('accept :NUM (port specifier)', () => {
|
|
||||||
const test = '@foo:bar.com:2225';
|
|
||||||
const found = linkify.find(test);
|
|
||||||
expect(found).toEqual(([{
|
|
||||||
href: "@foo:bar.com:2225",
|
|
||||||
type: "userid",
|
|
||||||
value: "@foo:bar.com:2225",
|
|
||||||
}]));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -3706,7 +3706,7 @@ eslint-module-utils@^2.7.2:
|
|||||||
debug "^3.2.7"
|
debug "^3.2.7"
|
||||||
find-up "^2.1.0"
|
find-up "^2.1.0"
|
||||||
|
|
||||||
eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.25.4:
|
eslint-plugin-import@^2.25.4:
|
||||||
version "2.25.4"
|
version "2.25.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1"
|
||||||
integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==
|
integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==
|
||||||
@ -5968,10 +5968,20 @@ lines-and-columns@^1.1.6:
|
|||||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||||
|
|
||||||
linkifyjs@^2.1.9:
|
linkify-element@^3.0.4:
|
||||||
version "2.1.9"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.9.tgz#af06e45a2866ff06c4766582590d098a4d584702"
|
resolved "https://registry.yarnpkg.com/linkify-element/-/linkify-element-3.0.4.tgz#3566a3b48d4c211a684f42a23a9964bf53f3a31a"
|
||||||
integrity sha512-74ivurkK6WHvHFozVaGtQWV38FzBwSTGNmJolEgFp7QgR2bl6ArUWlvT4GcHKbPe1z3nWYi+VUdDZk16zDOVug==
|
integrity sha512-xrj2Upv4/XUxvvczoDwojEnzKnfJCHlorAxYmdFPSGNwLz2sXYkYyB7Lw1flkGS7L0yS0dq/HwOotG0Kpaiaxw==
|
||||||
|
|
||||||
|
linkify-string@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkify-string/-/linkify-string-3.0.4.tgz#6abf1a5e436e800c729274ae08f5703484647f84"
|
||||||
|
integrity sha512-OnNqqRjlYXaXipIAbBC8sDXsSumI1ftatzFg141Pw9HEXWjTVLFcMZoKbFupshqWRavtNJ6QHLa+u6AlxxgeRw==
|
||||||
|
|
||||||
|
linkifyjs@^3.0.5:
|
||||||
|
version "3.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-3.0.5.tgz#99e51a3a0c0e232fcb63ebb89eea3ff923378f34"
|
||||||
|
integrity sha512-1Y9XQH65eQKA9p2xtk+zxvnTeQBG7rdAXSkUG97DmuI/Xhji9uaUzaWxRj6rf9YC0v8KKHkxav7tnLX82Sz5Fg==
|
||||||
|
|
||||||
loader-utils@^2.0.0:
|
loader-utils@^2.0.0:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
|
Loading…
Reference in New Issue
Block a user