summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-11-22 05:02:38 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-11-22 05:02:38 +0900
commit8cbb9614932ab684f2cf85624739369ed9e7757e (patch)
treedb5268320debed5bcbd9d961c7f284c68ea18e78
parentRefactoring (diff)
downloadmisskey-8cbb9614932ab684f2cf85624739369ed9e7757e.tar.gz
misskey-8cbb9614932ab684f2cf85624739369ed9e7757e.tar.bz2
misskey-8cbb9614932ab684f2cf85624739369ed9e7757e.zip
[MFM] Improve URL parsing
Fix #3368
-rw-r--r--src/mfm/parser.ts20
-rw-r--r--test/mfm.ts36
2 files changed, 46 insertions, 10 deletions
diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts
index 5acba7867b..047124e582 100644
--- a/src/mfm/parser.ts
+++ b/src/mfm/parser.ts
@@ -245,11 +245,25 @@ const mfm = P.createLanguage({
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/);
if (!match) return P.makeFailure(i, 'not a url');
let url = match[0];
- const before = input[i - 1];
+ let pendingBracket = 0;
+ const end = url.split('').findIndex(char => {
+ if (char == ')') {
+ if (pendingBracket > 0) {
+ pendingBracket--;
+ return false;
+ } else {
+ return true;
+ }
+ } else if (char == '(') {
+ pendingBracket++;
+ return false;
+ } else {
+ return false;
+ }
+ });
+ if (end > 0) url = url.substr(0, end);
if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.'));
if (url.endsWith(',')) url = url.substr(0, url.lastIndexOf(','));
- if (url.endsWith(')') && before == '(') url = url.substr(0, url.lastIndexOf(')'));
- if (url.endsWith(']') && before == '[') url = url.substr(0, url.lastIndexOf(']'));
return P.makeSuccess(i + url.length, url);
})
.map(x => makeNode('url', { url: x })),
diff --git a/test/mfm.ts b/test/mfm.ts
index d99bb2bac7..8447e798e2 100644
--- a/test/mfm.ts
+++ b/test/mfm.ts
@@ -381,6 +381,15 @@ describe('Text', () => {
], tokens);
});
+ it('ignore parent brackets 2', () => {
+ const tokens = analyze('(foo https://example.com/foo)');
+ assert.deepEqual([
+ text('(foo '),
+ node('url', { url: 'https://example.com/foo' }),
+ text(')')
+ ], tokens);
+ });
+
it('ignore parent brackets with internal brackets', () => {
const tokens = analyze('(https://example.com/foo(bar))');
assert.deepEqual([
@@ -391,13 +400,26 @@ describe('Text', () => {
});
});
- it('link', () => {
- const tokens = analyze('[foo](https://example.com)');
- assert.deepEqual([
- nodeWithChildren('link', [
- text('foo')
- ], { url: 'https://example.com', silent: false })
- ], tokens);
+ describe('link', () => {
+ it('simple', () => {
+ const tokens = analyze('[foo](https://example.com)');
+ assert.deepEqual([
+ nodeWithChildren('link', [
+ text('foo')
+ ], { url: 'https://example.com', silent: false })
+ ], tokens);
+ });
+
+ it('in text', () => {
+ const tokens = analyze('before[foo](https://example.com)after');
+ assert.deepEqual([
+ text('before'),
+ nodeWithChildren('link', [
+ text('foo')
+ ], { url: 'https://example.com', silent: false }),
+ text('after'),
+ ], tokens);
+ });
});
it('emoji', () => {