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 Feb 5, 2023
1 parent e7f70c6 commit 396abd9
Show file tree
Hide file tree
Showing 9 changed files with 103 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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
-->
## 0.23.4 (unreleased)

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

### Improvements
- Improve generation of brackets for links (#126)

Expand Down
15 changes: 10 additions & 5 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,19 +535,24 @@ 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/)
```

Special characters
type='embed'
```
[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>)
![Misskey.io](https://misskey.io/)
```

## 詳細
Expand All @@ -559,7 +564,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
13 changes: 9 additions & 4 deletions src/internal/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,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)');
});

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

test('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)');
});

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

test('fn', () => {
const input = '$[tada Hello]';
assert.strictEqual(mfm.toString(mfm.parse(input)), '$[tada Hello]');
Expand Down
66 changes: 54 additions & 12 deletions test/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,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 @@ -1056,7 +1056,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 @@ -1069,7 +1069,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 @@ -1086,26 +1086,66 @@ hoge`;
assert.deepStrictEqual(mfm.parse(input), output);
});

test('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);
});

test('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);
});

test('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', () => {
test('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')]
),
TEXT('.'),
];
assert.deepStrictEqual(mfm.parse(input), output);
});

test('nested', () => {
const input = 'official instance: [https://misskey.io/@ai**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 @@ -1126,7 +1166,7 @@ hoge`;
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[TEXT('[https://misskey.io/@ai')]
),
Expand All @@ -1136,12 +1176,13 @@ hoge`;
];
assert.deepStrictEqual(mfm.parse(input), output);
});

test('nested', () => {
const input = 'official instance: [**[https://misskey.io/@ai](https://misskey.io/@ai)**](https://misskey.io/@ai).';
const output = [
TEXT('official instance: '),
LINK(
false,
'plain',
N_URL('https://misskey.io/@ai'),
[
BOLD([
Expand All @@ -1159,18 +1200,19 @@ hoge`;
const input = '[@example](https://example.com)';
const output = [
LINK(
false,
'plain',
N_URL('https://example.com'),
[TEXT('@example')]
),
];
assert.deepStrictEqual(mfm.parse(input), output);
});

test('nested', () => {
const input = '[@example**@example**](https://example.com)';
const output = [
LINK(
false,
'plain',
N_URL('https://example.com'),
[
TEXT('@example'),
Expand All @@ -1188,7 +1230,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 @@ -1201,7 +1243,7 @@ hoge`;
const output = [
TEXT('('),
LINK(
false,
'plain',
N_URL('https://example.com/foo(bar)'),
[TEXT('foo')]
),
Expand All @@ -1215,7 +1257,7 @@ hoge`;
const output = [
TEXT('[test] foo '),
LINK(
false,
'plain',
N_URL('https://example.com'),
[TEXT('bar')]
),
Expand Down

0 comments on commit 396abd9

Please sign in to comment.