Skip to content

Commit

Permalink
add support for additional link modes
Browse files Browse the repository at this point in the history
  • Loading branch information
shibaobun committed Oct 15, 2022
1 parent 88daccc commit 9d5277b
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 28 deletions.
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 16.13.2
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
### Bugfixes
-->
## 0.24.0

### Features
- Add Remote media syntax for links (#127)

## 0.23.1

### Improvements
Expand Down
17 changes: 13 additions & 4 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,20 +535,29 @@ http://hoge.jp/abc
<h1 id="link">Inline: リンク</h2>

## 形式
silent=false
type='plain'
```
[Misskey.io](https://misskey.io/)
```

silent=true
type='plain' with special characters
```
[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)
```

type='silent'
```
?[Misskey.io](https://misskey.io/)
```

type='embed'
```
![Misskey.io](https://misskey.io/)
```

Special characters
```
[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)
```
## 詳細
- リンクラベルには再度InlineParserを適用する。ただし、リンクラベルではURL、リンク、メンションは使用できない。
Expand All @@ -559,7 +568,7 @@ Special characters
{
type: 'link',
props: {
silent: false,
type: 'plain'
url: {
type: 'url',
props: {
Expand Down
4 changes: 2 additions & 2 deletions etc/mfm-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function inspect(nodes: MfmNode[], action: (node: MfmNode) => void): void
export const ITALIC: (children: MfmInline[]) => NodeType<'italic'>;

// @public (undocumented)
export const LINK: (silent: boolean, url: MfmUrl, children: MfmInline[]) => NodeType<'link'>;
export const LINK: (type: 'plain' | 'silent' | 'embed', url: MfmUrl, children: MfmInline[]) => NodeType<'link'>;

// @public (undocumented)
export const MATH_BLOCK: (formula: string) => NodeType<'mathBlock'>;
Expand Down Expand Up @@ -127,7 +127,7 @@ export type MfmItalic = {
export type MfmLink = {
type: 'link';
props: {
silent: boolean;
type: 'plain' | 'silent' | 'embed';
url: MfmUrl;
};
children: MfmInline[];
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mfm-js",
"version": "0.23.1",
"version": "0.24.0",
"description": "An MFM parser implementation with TypeScript",
"main": "./built/index.js",
"types": "./built/index.d.ts",
Expand Down
13 changes: 9 additions & 4 deletions src/internal/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ export const language = P.createLanguage({
P.str('.'),
arg.sep(P.str(','), 1),
], 1).map(pairs => {
const result: Args = { };
const result: Args = {};
for (const pair of pairs) {
result[pair.k] = pair.v;
}
Expand Down Expand Up @@ -644,7 +644,7 @@ export const language = P.createLanguage({
const closeLabel = P.str(']');
return P.seq([
notLinkLabel,
P.alt([P.str('?['), P.str('[')]),
P.alt([P.str('?['), P.str('!['), P.str('[')]),
P.seq([
P.notMatch(P.alt([closeLabel, newLine])),
nest(labelInline),
Expand All @@ -654,10 +654,15 @@ export const language = P.createLanguage({
P.alt([r.urlAlt, r.url]),
P.str(')'),
]).map(result => {
const silent = (result[1] === '?[');
const mapping: {[key: string]: M.MfmLink['props']['type']} = {
'?[': 'silent',
'![': 'embed',
'[': 'plain',
};
const type: M.MfmLink['props']['type'] = mapping[result[1]];
const label = result[2];
const url: M.MfmUrl = result[5];
return M.LINK(silent, url, mergeText(label));
return M.LINK(type, url, mergeText(label));
});
},

Expand Down
10 changes: 7 additions & 3 deletions src/internal/util.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isMfmBlock, MfmInline, MfmNode, MfmText, TEXT } from '../node';
import { isMfmBlock, MfmInline, MfmNode, MfmText, MfmLink, TEXT } from '../node';

export function mergeText<T extends MfmNode>(nodes: ((T extends MfmInline ? MfmInline : MfmNode) | string)[]): (T | MfmText)[] {
const dest: (T | MfmText)[] = [];
Expand Down Expand Up @@ -91,8 +91,12 @@ export function stringifyNode(node: MfmNode): string {
}
}
case 'link': {
const prefix = node.props.silent ? '?' : '';
return `${ prefix }[${ stringifyTree(node.children) }](${ stringifyNode(node.props.url) })`;
const prefixMapping: {[key in MfmLink['props']['type']]: string} = {
'silent': '?',
'embed': '!',
'plain': '',
};
return `${ prefixMapping[node.props.type] }[${ stringifyTree(node.children) }](${ stringifyNode(node.props.url) })`;
}
case 'fn': {
const argFields = Object.keys(node.props.args).map(key => {
Expand Down
4 changes: 2 additions & 2 deletions src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,12 @@ export const N_URL = (value: string, brackets?: boolean): NodeType<'url'> => {
export type MfmLink = {
type: 'link';
props: {
silent: boolean;
type: 'plain' | 'silent' | 'embed';
url: MfmUrl;
};
children: MfmInline[];
};
export const LINK = (silent: boolean, url: MfmUrl, children: MfmInline[]): NodeType<'link'> => { return { type: 'link', props: { silent, url }, children }; };
export const LINK = (type: 'plain' | 'silent' | 'embed', url: MfmUrl, children: MfmInline[]): NodeType<'link'> => { return { type: 'link', props: { type, url }, children }; };

export type MfmFn = {
type: 'fn';
Expand Down
15 changes: 15 additions & 0 deletions test/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ after`;
assert.strictEqual(mfm.toString(mfm.parse(input)), '?[Ai](https://github.com/syuilo/ai)');
});

it('silent bracket link', () => {
const input = '?[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)';
assert.strictEqual(mfm.toString(mfm.parse(input)), '?[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)');
});

it('image link', () => {
const input = '![Ai logo](https://raw.githubusercontent.com/syuilo/ai/master/ai.svg)';
assert.strictEqual(mfm.toString(mfm.parse(input)), '![Ai logo](https://raw.githubusercontent.com/syuilo/ai/master/ai.svg)');
});

it('image bracket link', () => {
const input = '![#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)';
assert.strictEqual(mfm.toString(mfm.parse(input)), '![#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)');
});

it('fn', () => {
const input = '$[tada Hello]';
assert.strictEqual(mfm.toString(mfm.parse(input)), '$[tada Hello]');
Expand Down
63 changes: 51 additions & 12 deletions test/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ hoge`;
const input = '[official instance](https://misskey.io/@ai).';
const output = [
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[TEXT('official instance')]
),
Expand All @@ -1036,7 +1036,7 @@ hoge`;
const input = '?[official instance](https://misskey.io/@ai).';
const output = [
LINK(
true,
'silent',
N_URL('https://misskey.io/@ai'),
[TEXT('official instance')]
),
Expand All @@ -1049,7 +1049,7 @@ hoge`;
const input = '[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>).';
const output = [
LINK(
false,
'plain',
N_URL('https://misskey.io/explore/tags/藍ちゃファンクラブ', true),
[TEXT('#藍ちゃファンクラブ')]
),
Expand All @@ -1058,13 +1058,52 @@ hoge`;
assert.deepStrictEqual(mfm.parse(input), output);
});

it('embed flag', () => {
const input = '![image](https://raw.githubusercontent.com/syuilo/ai/master/ai.svg).';
const output = [
LINK(
'embed',
N_URL('https://raw.githubusercontent.com/syuilo/ai/master/ai.svg'),
[TEXT('image')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
});

it('with angle brackets silent url', () => {
const input = '?[image](<https://raw.githubusercontent.com/syuilo/ai/master/ai.svg>).';
const output = [
LINK(
'silent',
N_URL('https://raw.githubusercontent.com/syuilo/ai/master/ai.svg', true),
[TEXT('image')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
});

it('with angle brackets embed url', () => {
const input = '![image](<https://raw.githubusercontent.com/syuilo/ai/master/ai.svg>).';
const output = [
LINK(
'embed',
N_URL('https://raw.githubusercontent.com/syuilo/ai/master/ai.svg', true),
[TEXT('image')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
});

describe('cannot nest a url in a link label', () => {
it('basic', () => {
const input = 'official instance: [https://misskey.io/@ai](https://misskey.io/@ai).';
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[TEXT('https://misskey.io/@ai')]
),
Expand All @@ -1077,7 +1116,7 @@ hoge`;
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[
TEXT('https://misskey.io/@ai'),
Expand All @@ -1098,7 +1137,7 @@ hoge`;
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[TEXT('[https://misskey.io/@ai')]
),
Expand All @@ -1113,7 +1152,7 @@ hoge`;
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[
BOLD([
Expand All @@ -1131,7 +1170,7 @@ hoge`;
const input = '[@example](https://example.com)';
const output = [
LINK(
false,
'plain',
N_URL('https://example.com'),
[TEXT('@example')]
),
Expand All @@ -1142,7 +1181,7 @@ hoge`;
const input = '[@example**@example**](https://example.com)';
const output = [
LINK(
false,
'plain',
N_URL('https://example.com'),
[
TEXT('@example'),
Expand All @@ -1160,7 +1199,7 @@ hoge`;
const input = '[foo](https://example.com/foo(bar))';
const output = [
LINK(
false,
'plain',
N_URL('https://example.com/foo(bar)'),
[TEXT('foo')]
),
Expand All @@ -1173,7 +1212,7 @@ hoge`;
const output = [
TEXT('('),
LINK(
false,
'plain',
N_URL('https://example.com/foo(bar)'),
[TEXT('foo')]
),
Expand All @@ -1187,7 +1226,7 @@ hoge`;
const output = [
TEXT('[test] foo '),
LINK(
false,
'plain',
N_URL('https://example.com'),
[TEXT('bar')]
),
Expand Down

0 comments on commit 9d5277b

Please sign in to comment.