Skip to content

Commit

Permalink
Use MfmUrl AST in MfmLink AST
Browse files Browse the repository at this point in the history
  • Loading branch information
shibaobun committed Feb 5, 2023
1 parent ae92c2a commit e7f70c6
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 63 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
### Bugfixes
-->
## 0.23.4 (unreleased)

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

## 0.23.3
- tweak fn parsing
Expand Down
33 changes: 22 additions & 11 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,10 @@ __bold__
- 内容には再度InlineParserを適用する。
- 内容を空にすることはできない。

構文1,3のみ:
構文1,3のみ:
- 内容にはすべての文字、改行が使用できる。

構文2のみ:
構文2のみ:
- 内容には`[a-z0-9 \t]i`にマッチする文字が使用できる。

## ノード
Expand Down Expand Up @@ -289,11 +289,11 @@ _italic_
- 内容には再度InlineParserを適用する。
- 内容を空にすることはできない。

構文1のみ:
構文1のみ:
- 内容にはすべての文字、改行が使用できる。

構文2,3のみ:
※1つ目の`*``_`を開始記号と呼ぶ。
構文2,3のみ:
※1つ目の`*``_`を開始記号と呼ぶ。
- 内容には`[a-z0-9 \t]i`にマッチする文字が使用できる。
- 開始記号の前の文字が`[a-z0-9]i`に一致しない時にイタリック文字として判定される。

Expand Down Expand Up @@ -326,10 +326,10 @@ _italic_
- 内容には再度InlineParserを適用する。
- 内容を空にすることはできない。

構文1のみ:
構文1のみ:
- 内容には`~`、改行以外の文字を使用できる。

構文2のみ:
構文2のみ:
- 内容にはすべての文字、改行が使用できる。

## ノード
Expand Down Expand Up @@ -488,12 +488,12 @@ http://hoge.jp/abc
```

## 詳細
構文1のみ:
構文1のみ:
- 内容には`[.,a-z0-9_/:%#@$&?!~=+-]i`にマッチする文字を使用できる。
- 内容には対になっている括弧を使用できる。対象: `( )` `[ ]`
- `.``,`は最後の文字にできない。

構文2のみ:
構文2のみ:
- 内容には改行、スペース以外の文字を使用できる。

## ノード
Expand Down Expand Up @@ -545,6 +545,11 @@ silent=true
?[Misskey.io](https://misskey.io/)
```

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

## 詳細
- 表示テキストには再度InlineParserを適用する。ただし、表示テキストではURL、リンク、メンションは使用できない。

Expand All @@ -555,7 +560,13 @@ silent=true
type: 'link',
props: {
silent: false,
url: 'https://misskey.io/'
url: {
type: 'url',
props: {
url: 'https://misskey.io/@ai',
brackets: false
}
},
},
children: [
{
Expand Down Expand Up @@ -665,7 +676,7 @@ abc
```js
{
type: 'text',
props:
props:
text: 'abc'
}
}
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: string, children: MfmInline[]) => NodeType<'link'>;
export const LINK: (silent: boolean, url: MfmUrl, children: MfmInline[]) => NodeType<'link'>;

// @public (undocumented)
export const MATH_BLOCK: (formula: string) => NodeType<'mathBlock'>;
Expand Down Expand Up @@ -128,7 +128,7 @@ export type MfmLink = {
type: 'link';
props: {
silent: boolean;
url: string;
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.3",
"version": "0.23.4",
"description": "An MFM parser implementation with TypeScript",
"main": "./built/index.js",
"types": "./built/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/internal/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ export const language = P.createLanguage({
const silent = (result[1] === '?[');
const label = result[2];
const url: M.MfmUrl = result[5];
return M.LINK(silent, url.props.url, mergeText(label));
return M.LINK(silent, url, mergeText(label));
});
},

Expand Down
2 changes: 1 addition & 1 deletion src/internal/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function stringifyNode(node: MfmNode): string {
}
case 'link': {
const prefix = node.props.silent ? '?' : '';
return `${ prefix }[${ stringifyTree(node.children) }](${ node.props.url })`;
return `${ prefix }[${ 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 @@ -157,11 +157,11 @@ export type MfmLink = {
type: 'link';
props: {
silent: boolean;
url: string;
url: MfmUrl;
};
children: MfmInline[];
};
export const LINK = (silent: boolean, url: string, children: MfmInline[]): NodeType<'link'> => { return { type: 'link', props: { silent, url }, children }; };
export const LINK = (silent: boolean, url: MfmUrl, children: MfmInline[]): NodeType<'link'> => { return { type: 'link', props: { silent, url }, children }; };

export type MfmFn = {
type: 'fn';
Expand Down
7 changes: 6 additions & 1 deletion test/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ after`;
test('quote', () => {
const input = `
> abc
>
>
> 123
`;

Expand Down Expand Up @@ -132,6 +132,11 @@ after`;
assert.strictEqual(mfm.toString(mfm.parse(input)), '[Ai](https://github.com/syuilo/ai)');
});

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

test('silent link', () => {
const input = '?[Ai](https://github.com/syuilo/ai)';
assert.strictEqual(mfm.toString(mfm.parse(input)), '?[Ai](https://github.com/syuilo/ai)');
Expand Down
118 changes: 74 additions & 44 deletions test/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1042,9 +1042,11 @@ hoge`;
test('basic', () => {
const input = '[official instance](https://misskey.io/@ai).';
const output = [
LINK(false, 'https://misskey.io/@ai', [
TEXT('official instance')
]),
LINK(
false,
N_URL('https://misskey.io/@ai'),
[TEXT('official instance')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
Expand All @@ -1053,20 +1055,24 @@ hoge`;
test('silent flag', () => {
const input = '?[official instance](https://misskey.io/@ai).';
const output = [
LINK(true, 'https://misskey.io/@ai', [
TEXT('official instance')
]),
LINK(
true,
N_URL('https://misskey.io/@ai'),
[TEXT('official instance')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
});

test('with angle brackets url', () => {
const input = '[official instance](<https://misskey.io/@ai>).';
const input = '[#藍ちゃファンクラブ](<https://misskey.io/explore/tags/藍ちゃファンクラブ>).';
const output = [
LINK(false, 'https://misskey.io/@ai', [
TEXT('official instance')
]),
LINK(
false,
N_URL('https://misskey.io/explore/tags/藍ちゃファンクラブ', true),
[TEXT('#藍ちゃファンクラブ')]
),
TEXT('.')
];
assert.deepStrictEqual(mfm.parse(input), output);
Expand All @@ -1085,9 +1091,11 @@ hoge`;
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'),
]),
LINK(
false,
N_URL('https://misskey.io/@ai'),
[TEXT('https://misskey.io/@ai')]
),
TEXT('.'),
];
assert.deepStrictEqual(mfm.parse(input), output);
Expand All @@ -1096,12 +1104,16 @@ hoge`;
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'),
BOLD([
LINK(
false,
N_URL('https://misskey.io/@ai'),
[
TEXT('https://misskey.io/@ai'),
]),
]),
BOLD([
TEXT('https://misskey.io/@ai'),
]),
]
),
TEXT('.'),
];
assert.deepStrictEqual(mfm.parse(input), output);
Expand All @@ -1113,9 +1125,11 @@ hoge`;
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'),
]),
LINK(
false,
N_URL('https://misskey.io/@ai'),
[TEXT('[https://misskey.io/@ai')]
),
TEXT(']('),
N_URL('https://misskey.io/@ai'),
TEXT(').'),
Expand All @@ -1126,11 +1140,15 @@ hoge`;
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', [
BOLD([
TEXT('[https://misskey.io/@ai](https://misskey.io/@ai)'),
]),
]),
LINK(
false,
N_URL('https://misskey.io/@ai'),
[
BOLD([
TEXT('[https://misskey.io/@ai](https://misskey.io/@ai)'),
]),
]
),
TEXT('.'),
];
});
Expand All @@ -1140,21 +1158,27 @@ hoge`;
test('basic', () => {
const input = '[@example](https://example.com)';
const output = [
LINK(false, 'https://example.com', [
TEXT('@example'),
]),
LINK(
false,
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, 'https://example.com', [
TEXT('@example'),
BOLD([
LINK(
false,
N_URL('https://example.com'),
[
TEXT('@example'),
]),
]),
BOLD([
TEXT('@example'),
]),
]
),
];
assert.deepStrictEqual(mfm.parse(input), output);
});
Expand All @@ -1163,9 +1187,11 @@ hoge`;
test('with brackets', () => {
const input = '[foo](https://example.com/foo(bar))';
const output = [
LINK(false, 'https://example.com/foo(bar)', [
TEXT('foo')
]),
LINK(
false,
N_URL('https://example.com/foo(bar)'),
[TEXT('foo')]
),
];
assert.deepStrictEqual(mfm.parse(input), output);
});
Expand All @@ -1174,9 +1200,11 @@ hoge`;
const input = '([foo](https://example.com/foo(bar)))';
const output = [
TEXT('('),
LINK(false, 'https://example.com/foo(bar)', [
TEXT('foo')
]),
LINK(
false,
N_URL('https://example.com/foo(bar)'),
[TEXT('foo')]
),
TEXT(')'),
];
assert.deepStrictEqual(mfm.parse(input), output);
Expand All @@ -1186,9 +1214,11 @@ hoge`;
const input = '[test] foo [bar](https://example.com)';
const output = [
TEXT('[test] foo '),
LINK(false, 'https://example.com', [
TEXT('bar')
]),
LINK(
false,
N_URL('https://example.com'),
[TEXT('bar')]
),
];
assert.deepStrictEqual(mfm.parse(input), output);
});
Expand Down Expand Up @@ -1369,7 +1399,7 @@ hoge`;
];
assert.deepStrictEqual(mfm.parse(input, { nestLimit: 2 }), output);
});

test('tag', () => {
const input = '<b><b><s>abc</s></b></b>';
const output = [
Expand Down

0 comments on commit e7f70c6

Please sign in to comment.