Add angle bracket covered url syntax to mfm (#4483)
* Add angle bracket covered url syntax to mfm * Fix path * Fix match * Fix index
This commit is contained in:
parent
0f65b1bcc5
commit
38656103c0
10 changed files with 37 additions and 13 deletions
|
@ -1,5 +1,6 @@
|
||||||
import { parseFragment, DefaultTreeDocumentFragment } from 'parse5';
|
import { parseFragment, DefaultTreeDocumentFragment } from 'parse5';
|
||||||
import { URL } from 'url';
|
import { URL } from 'url';
|
||||||
|
import { urlRegex } from './prelude';
|
||||||
|
|
||||||
export function fromHtml(html: string): string {
|
export function fromHtml(html: string): string {
|
||||||
if (html == null) return null;
|
if (html == null) return null;
|
||||||
|
@ -14,7 +15,7 @@ export function fromHtml(html: string): string {
|
||||||
|
|
||||||
return text.trim();
|
return text.trim();
|
||||||
|
|
||||||
function getText(node: any) {
|
function getText(node: any): string {
|
||||||
if (node.nodeName == '#text') return node.value;
|
if (node.nodeName == '#text') return node.value;
|
||||||
|
|
||||||
if (node.childNodes) {
|
if (node.childNodes) {
|
||||||
|
@ -41,7 +42,7 @@ export function fromHtml(html: string): string {
|
||||||
|
|
||||||
// ハッシュタグ / hrefがない / txtがURL
|
// ハッシュタグ / hrefがない / txtがURL
|
||||||
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
|
if ((rel && rel.value.match('tag') !== null) || !href || href.value == txt) {
|
||||||
text += txt;
|
text += txt.match(urlRegex) ? txt : `<${txt}>`;
|
||||||
// メンション
|
// メンション
|
||||||
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) {
|
} else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) {
|
||||||
const part = txt.split('@');
|
const part = txt.split('@');
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as P from 'parsimmon';
|
import * as P from 'parsimmon';
|
||||||
import { createLeaf, createTree } from './types';
|
import { createLeaf, createTree, urlRegex } from './prelude';
|
||||||
import { takeWhile, cumulativeSum } from '../prelude/array';
|
import { takeWhile, cumulativeSum } from '../prelude/array';
|
||||||
import parseAcct from '../misc/acct/parse';
|
import parseAcct from '../misc/acct/parse';
|
||||||
import { toUnicode } from 'punycode';
|
import { toUnicode } from 'punycode';
|
||||||
|
@ -154,9 +154,16 @@ export const mfmLanguage = P.createLanguage({
|
||||||
url: () => {
|
url: () => {
|
||||||
return P((input, i) => {
|
return P((input, i) => {
|
||||||
const text = input.substr(i);
|
const text = input.substr(i);
|
||||||
const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/);
|
const match = text.match(urlRegex);
|
||||||
if (!match) return P.makeFailure(i, 'not a url');
|
let url: string;
|
||||||
let url = match[0];
|
if (!match) {
|
||||||
|
const match = text.match(/^<(https?:\/\/.*?)>/);
|
||||||
|
if (!match)
|
||||||
|
return P.makeFailure(i, 'not a url');
|
||||||
|
url = match[1];
|
||||||
|
i += 2;
|
||||||
|
} else
|
||||||
|
url = match[0];
|
||||||
url = removeOrphanedBrackets(url);
|
url = removeOrphanedBrackets(url);
|
||||||
if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.'));
|
if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.'));
|
||||||
if (url.endsWith(',')) url = url.substr(0, url.lastIndexOf(','));
|
if (url.endsWith(',')) url = url.substr(0, url.lastIndexOf(','));
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as A from '../prelude/array';
|
import * as A from '../prelude/array';
|
||||||
import * as S from '../prelude/string';
|
import * as S from '../prelude/string';
|
||||||
import { MfmForest, MfmTree } from './types';
|
import { MfmForest, MfmTree } from './prelude';
|
||||||
import { createTree, createLeaf } from '../prelude/tree';
|
import { createTree, createLeaf } from '../prelude/tree';
|
||||||
|
|
||||||
function isEmptyTextTree(t: MfmTree): boolean {
|
function isEmptyTextTree(t: MfmTree): boolean {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mfmLanguage } from './language';
|
import { mfmLanguage } from './language';
|
||||||
import { MfmForest } from './types';
|
import { MfmForest } from './prelude';
|
||||||
import { normalize } from './normalize';
|
import { normalize } from './normalize';
|
||||||
|
|
||||||
export function parse(source: string): MfmForest {
|
export function parse(source: string): MfmForest {
|
||||||
|
|
|
@ -35,3 +35,5 @@ export function createLeaf(type: string, props: any): MfmTree {
|
||||||
export function createTree(type: string, children: MfmForest, props: any): MfmTree {
|
export function createTree(type: string, children: MfmForest, props: any): MfmTree {
|
||||||
return T.createTree({ type, props }, children);
|
return T.createTree({ type, props }, children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const urlRegex = /^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.,=\+\-]+/;
|
|
@ -2,7 +2,7 @@ import { JSDOM } from 'jsdom';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { INote } from '../models/note';
|
import { INote } from '../models/note';
|
||||||
import { intersperse } from '../prelude/array';
|
import { intersperse } from '../prelude/array';
|
||||||
import { MfmForest, MfmTree } from './types';
|
import { MfmForest, MfmTree } from './prelude';
|
||||||
|
|
||||||
export function toHtml(tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) {
|
export function toHtml(tokens: MfmForest, mentionedRemoteUsers: INote['mentionedRemoteUsers'] = []) {
|
||||||
if (tokens == null) {
|
if (tokens == null) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { EmojiNode, MfmForest } from '../mfm/types';
|
import { EmojiNode, MfmForest } from '../mfm/prelude';
|
||||||
import { preorderF } from '../prelude/tree';
|
import { preorderF } from '../prelude/tree';
|
||||||
import { unique } from '../prelude/array';
|
import { unique } from '../prelude/array';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { HashtagNode, MfmForest } from '../mfm/types';
|
import { HashtagNode, MfmForest } from '../mfm/prelude';
|
||||||
import { preorderF } from '../prelude/tree';
|
import { preorderF } from '../prelude/tree';
|
||||||
import { unique } from '../prelude/array';
|
import { unique } from '../prelude/array';
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// test is located in test/extract-mentions
|
// test is located in test/extract-mentions
|
||||||
|
|
||||||
import { MentionNode, MfmForest } from '../mfm/types';
|
import { MentionNode, MfmForest } from '../mfm/prelude';
|
||||||
import { preorderF } from '../prelude/tree';
|
import { preorderF } from '../prelude/tree';
|
||||||
|
|
||||||
export default function(mfmForest: MfmForest): MentionNode['props'][] {
|
export default function(mfmForest: MfmForest): MentionNode['props'][] {
|
||||||
|
|
16
test/mfm.ts
16
test/mfm.ts
|
@ -12,7 +12,7 @@ import * as assert from 'assert';
|
||||||
|
|
||||||
import { parse, parsePlain } from '../src/mfm/parse';
|
import { parse, parsePlain } from '../src/mfm/parse';
|
||||||
import { toHtml } from '../src/mfm/toHtml';
|
import { toHtml } from '../src/mfm/toHtml';
|
||||||
import { createTree as tree, createLeaf as leaf, MfmTree } from '../src/mfm/types';
|
import { createTree as tree, createLeaf as leaf, MfmTree } from '../src/mfm/prelude';
|
||||||
import { removeOrphanedBrackets } from '../src/mfm/language';
|
import { removeOrphanedBrackets } from '../src/mfm/language';
|
||||||
|
|
||||||
function text(text: string): MfmTree {
|
function text(text: string): MfmTree {
|
||||||
|
@ -840,6 +840,20 @@ describe('MFM', () => {
|
||||||
text(')')
|
text(')')
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('ignore non-ascii characters contained url without angle brackets', () => {
|
||||||
|
const tokens = parse('https://大石泉すき.example.com');
|
||||||
|
assert.deepStrictEqual(tokens, [
|
||||||
|
text('https://大石泉すき.example.com')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('match non-ascii characters contained url with angle brackets', () => {
|
||||||
|
const tokens = parse('<https://大石泉すき.example.com>');
|
||||||
|
assert.deepStrictEqual(tokens, [
|
||||||
|
leaf('url', { url: 'https://大石泉すき.example.com' })
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('link', () => {
|
describe('link', () => {
|
||||||
|
|
Loading…
Reference in a new issue