[MFM] Improve hashtag detection

This commit is contained in:
syuilo 2018-11-27 02:08:51 +09:00
parent 24ef98eb01
commit 2c6bad2501
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
2 changed files with 39 additions and 10 deletions

View file

@ -30,17 +30,23 @@ function makeNodeWithChildren(name: string, children: Node[], props?: any): Node
} }
function getTrailingPosition(x: string): number { function getTrailingPosition(x: string): number {
let pendingBracket = 0; const brackets = [
['(', ')'],
['「', '」'],
];
const pendingBrackets = [] as any;
const end = x.split('').findIndex(char => { const end = x.split('').findIndex(char => {
if (char == ')') { const closeMatch = brackets.map(x => x[1]).indexOf(char);
if (pendingBracket > 0) { const openMatch = brackets.map(x => x[0]).indexOf(char);
pendingBracket--; if (closeMatch != -1) {
if (pendingBrackets[closeMatch] > 0) {
pendingBrackets[closeMatch]--;
return false; return false;
} else { } else {
return true; return true;
} }
} else if (char == '(') { } else if (openMatch != -1) {
pendingBracket++; pendingBrackets[openMatch] = (pendingBrackets[openMatch] || 0) + 1;
return false; return false;
} else { } else {
return false; return false;
@ -156,7 +162,7 @@ const mfm = P.createLanguage({
let hashtag = match[1]; let hashtag = match[1];
hashtag = hashtag.substr(0, getTrailingPosition(hashtag)); hashtag = hashtag.substr(0, getTrailingPosition(hashtag));
if (hashtag.match(/^[0-9]+$/)) return P.makeFailure(i, 'not a hashtag'); if (hashtag.match(/^[0-9]+$/)) return P.makeFailure(i, 'not a hashtag');
if (!['\n', ' ', '(', null, undefined].includes(input[i - 1])) return P.makeFailure(i, 'require space before "#"'); if (!['\n', ' ', '(', '「', null, undefined].includes(input[i - 1])) return P.makeFailure(i, 'require space before "#"');
return P.makeSuccess(i + ('#' + hashtag).length, makeNode('hashtag', { hashtag: hashtag })); return P.makeSuccess(i + ('#' + hashtag).length, makeNode('hashtag', { hashtag: hashtag }));
}), }),
//#endregion //#endregion

View file

@ -213,21 +213,44 @@ describe('Text', () => {
}); });
it('with brackets', () => { it('with brackets', () => {
const tokens = analyze('(#foo)'); const tokens1 = analyze('(#foo)');
assert.deepEqual([ assert.deepEqual([
text('('), text('('),
node('hashtag', { hashtag: 'foo' }), node('hashtag', { hashtag: 'foo' }),
text(')'), text(')'),
], tokens1);
const tokens2 = analyze('「#foo」');
assert.deepEqual([
text('「'),
node('hashtag', { hashtag: 'foo' }),
text('」'),
], tokens2);
});
it('with mixed brackets', () => {
const tokens = analyze('「#foo(bar)」');
assert.deepEqual([
text('「'),
node('hashtag', { hashtag: 'foo(bar)' }),
text('」'),
], tokens); ], tokens);
}); });
it('with brackets (space before)', () => { it('with brackets (space before)', () => {
const tokens = analyze('(bar #foo)'); const tokens1 = analyze('(bar #foo)');
assert.deepEqual([ assert.deepEqual([
text('(bar '), text('(bar '),
node('hashtag', { hashtag: 'foo' }), node('hashtag', { hashtag: 'foo' }),
text(')'), text(')'),
], tokens); ], tokens1);
const tokens2 = analyze('「bar #foo」');
assert.deepEqual([
text('「bar '),
node('hashtag', { hashtag: 'foo' }),
text('」'),
], tokens2);
}); });
it('disallow number only', () => { it('disallow number only', () => {