diff --git a/package.json b/package.json index d50a3625c428dc07cffc49ebe1b8a74e21a6dfba..bccb2df05071830cea1acd82824f691932967db3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mfm-js", - "version": "0.12.0", + "version": "0.0.0", "description": "An MFM parser implementation with PEG.js", "main": "./built/index.js", "types": "./built/index.d.ts", diff --git a/src/parser.pegjs b/src/parser.pegjs index 148b3ef62db3d65ba72a8d6d85378216346c807d..b517237b33da12abd58f80f6889f2490fa44f124 100644 --- a/src/parser.pegjs +++ b/src/parser.pegjs @@ -333,7 +333,7 @@ urlBracketPair // inline: link link - = silent:"?"? "[" label:linkLabel "](" url:linkUrl ")" + = silent:"?"? "[" label:linkLabelPart+ "](" url:linkUrl ")" { return createNode('link', { silent: (silent != null), @@ -341,8 +341,10 @@ link }, mergeText(label)); } -linkLabel - = (!"]" n:inline { return n; })+ +linkLabelPart + = url { return text(); /* text node */ } + / link { return text(); /* text node */ } + / !"]" n:inline { return n; } linkUrl = url { return text(); } @@ -382,7 +384,7 @@ fnArg // inline: text text - = . + = . /* text node */ // // General diff --git a/test/main.ts b/test/main.ts index 909aad444e60f57576204b455ec311347029cb6f..7ec63038de46e271c4f9e221864a8d1331bb7d4c 100644 --- a/test/main.ts +++ b/test/main.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import { extract, inspect, parse, parsePlain, toString } from '../built/index'; import { createNode } from '../built/util'; import { - TEXT, CENTER, FN, UNI_EMOJI, MENTION, EMOJI_CODE, HASHTAG, N_URL, BOLD, SMALL, ITALIC, STRIKE, QUOTE, MATH_BLOCK, SEARCH, CODE_BLOCK + TEXT, CENTER, FN, UNI_EMOJI, MENTION, EMOJI_CODE, HASHTAG, N_URL, BOLD, SMALL, ITALIC, STRIKE, QUOTE, MATH_BLOCK, SEARCH, CODE_BLOCK, LINK } from './node'; describe('text', () => { @@ -423,7 +423,53 @@ describe('url', () => { }); }); -// link +describe('link', () => { + it('basic', () => { + const input = '[official instance](https://misskey.io/@ai).'; + const output = [ + LINK(false, 'https://misskey.io/@ai', [ + TEXT('official instance') + ]), + TEXT('.') + ]; + assert.deepStrictEqual(parse(input), output); + }); + + it('silent flag', () => { + const input = '?[official instance](https://misskey.io/@ai).'; + const output = [ + LINK(true, 'https://misskey.io/@ai', [ + TEXT('official instance') + ]), + TEXT('.') + ]; + assert.deepStrictEqual(parse(input), output); + }); + + it('do not yield url node even if label is recognisable as a url', () => { + const input = 'official instance: [https://misskey.io/@ai](https://misskey.io/@ai).'; + const output = [ + TEXT('official instance: '), + LINK(false, 'https://misskey.io/@ai', [ + TEXT('https://misskey.io/@ai') + ]), + TEXT('.') + ]; + assert.deepStrictEqual(parse(input), output); + }); + + it('do not yield link node even if label is recognisable as a link', () => { + const input = 'official instance: [[https://misskey.io/@ai](https://misskey.io/@ai)](https://misskey.io/@ai).'; + const output = [ + TEXT('official instance: '), + LINK(false, 'https://misskey.io/@ai', [ + TEXT('[https://misskey.io/@ai](https://misskey.io/@ai)') + ]), + TEXT('.') + ]; + assert.deepStrictEqual(parse(input), output); + }); +}); describe('fn', () => { it('basic', () => { @@ -497,10 +543,20 @@ describe('inspect API', () => { describe('extract API', () => { it('basic', () => { - const nodes = parse('abc:hoge:[tada 123:hoge:]:piyo:'); + const nodes = parse('@hoge @piyo @bebeyo'); + const expect = [ + MENTION('hoge', null, '@hoge'), + MENTION('piyo', null, '@piyo'), + MENTION('bebeyo', null, '@bebeyo') + ]; + assert.deepStrictEqual(extract(nodes, 'mention'), expect); + }); + + it('nested', () => { + const nodes = parse('abc:hoge:[tada 123 @hoge :foo:]:piyo:'); const expect = [ EMOJI_CODE('hoge'), - EMOJI_CODE('hoge'), + EMOJI_CODE('foo'), EMOJI_CODE('piyo') ]; assert.deepStrictEqual(extract(nodes, 'emojiCode'), expect);