securemark 0.294.3 → 0.294.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.js +164 -144
- package/markdown.d.ts +3 -12
- package/package.json +3 -3
- package/src/combinator/control/manipulation/fence.ts +2 -0
- package/src/combinator/control/manipulation/indent.ts +1 -1
- package/src/combinator/control/manipulation/match.ts +11 -8
- package/src/parser/api/parse.test.ts +3 -3
- package/src/parser/block/blockquote.test.ts +3 -9
- package/src/parser/block/blockquote.ts +4 -4
- package/src/parser/block/dlist.ts +4 -4
- package/src/parser/block/extension/example.ts +1 -3
- package/src/parser/block/extension/fig.test.ts +0 -1
- package/src/parser/block/extension/fig.ts +6 -6
- package/src/parser/block/extension/figbase.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +1 -1
- package/src/parser/block/extension/figure.ts +6 -6
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/table.ts +4 -4
- package/src/parser/block/heading.ts +4 -4
- package/src/parser/block/reply/cite.ts +2 -2
- package/src/parser/block/reply/quote.ts +2 -2
- package/src/parser/block/sidefence.test.ts +1 -3
- package/src/parser/block/sidefence.ts +4 -4
- package/src/parser/block/table.ts +2 -2
- package/src/parser/block.ts +1 -1
- package/src/parser/header.ts +3 -3
- package/src/parser/inline/autolink/account.test.ts +18 -17
- package/src/parser/inline/autolink/account.ts +14 -20
- package/src/parser/inline/autolink/anchor.test.ts +2 -1
- package/src/parser/inline/autolink/anchor.ts +10 -13
- package/src/parser/inline/autolink/channel.test.ts +6 -6
- package/src/parser/inline/autolink/channel.ts +28 -32
- package/src/parser/inline/autolink/email.test.ts +19 -19
- package/src/parser/inline/autolink/email.ts +7 -7
- package/src/parser/inline/autolink/hashnum.test.ts +20 -20
- package/src/parser/inline/autolink/hashnum.ts +6 -8
- package/src/parser/inline/autolink/hashtag.test.ts +27 -27
- package/src/parser/inline/autolink/hashtag.ts +15 -16
- package/src/parser/inline/autolink/url.test.ts +6 -6
- package/src/parser/inline/autolink/url.ts +5 -4
- package/src/parser/inline/autolink.ts +4 -5
- package/src/parser/inline/code.ts +12 -18
- package/src/parser/inline/deletion.test.ts +1 -1
- package/src/parser/inline/deletion.ts +3 -3
- package/src/parser/inline/emstrong.ts +3 -3
- package/src/parser/inline/extension/indexer.ts +1 -1
- package/src/parser/inline/html.test.ts +1 -0
- package/src/parser/inline/html.ts +1 -1
- package/src/parser/inline/insertion.test.ts +1 -1
- package/src/parser/inline/insertion.ts +3 -3
- package/src/parser/inline/italic.test.ts +2 -2
- package/src/parser/inline/italic.ts +3 -3
- package/src/parser/inline/link.test.ts +0 -1
- package/src/parser/inline/link.ts +3 -3
- package/src/parser/inline/mark.test.ts +1 -1
- package/src/parser/inline/mark.ts +3 -3
- package/src/parser/inline/remark.ts +3 -3
- package/src/parser/inline.test.ts +11 -11
- package/src/parser/inline.ts +2 -0
- package/src/parser/source/text.ts +8 -4
- package/src/parser/util.ts +1 -1
- package/src/parser/visibility.ts +4 -6
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { CodeParser } from '../inline';
|
|
2
2
|
import { List, Data } from '../../combinator/data/parser';
|
|
3
|
-
import {
|
|
4
|
-
import { Backtrack } from '../context';
|
|
3
|
+
import { match } from '../../combinator';
|
|
5
4
|
import { invalid } from '../util';
|
|
6
5
|
import { html } from 'typed-dom/dom';
|
|
7
6
|
|
|
8
|
-
export const code: CodeParser =
|
|
9
|
-
/(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
? new List([new Data(html('code', {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}, whole))])
|
|
20
|
-
: new List([new Data(opener)]),
|
|
21
|
-
true),
|
|
22
|
-
false,
|
|
23
|
-
[3 | Backtrack.bracket]);
|
|
7
|
+
export const code: CodeParser = match(
|
|
8
|
+
/(`+)(?!`)([^\n]*?)(?:((?<!`)\1(?!`))|(?=$|\n))/y,
|
|
9
|
+
([whole, opener, body, closer]) => () =>
|
|
10
|
+
closer
|
|
11
|
+
? new List([new Data(html('code', { 'data-src': whole }, format(body)))])
|
|
12
|
+
: body
|
|
13
|
+
? new List([new Data(html('code', {
|
|
14
|
+
class: 'invalid',
|
|
15
|
+
...invalid('code', 'syntax', `Missing the closing symbol "${opener}"`)
|
|
16
|
+
}, whole))])
|
|
17
|
+
: new List([new Data(opener)]));
|
|
24
18
|
|
|
25
19
|
function format(text: string): string {
|
|
26
20
|
return text.length > 2
|
|
@@ -13,7 +13,7 @@ describe('Unit: parser/inline/deletion', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('~'), ctx), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('~~'), ctx), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('~~a'), ctx), [['~~', 'a'], '']);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('~~a~'), ctx), [['~~', 'a
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('~~a~'), ctx), [['~~', 'a~'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser(' ~~a~~'), ctx), undefined);
|
|
18
18
|
});
|
|
19
19
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DeletionParser } from '../inline';
|
|
2
2
|
import { Recursion, Command } from '../context';
|
|
3
3
|
import { List, Data } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence,
|
|
4
|
+
import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { blankWith } from '../visibility';
|
|
7
7
|
import { unwrap, repeat } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
|
-
export const deletion: DeletionParser = lazy(() =>
|
|
10
|
+
export const deletion: DeletionParser = lazy(() =>
|
|
11
11
|
precedence(0, repeat('~~', surround(
|
|
12
12
|
'',
|
|
13
13
|
recursion(Recursion.inline,
|
|
@@ -18,4 +18,4 @@ export const deletion: DeletionParser = lazy(() => validate('~~',
|
|
|
18
18
|
'~~', false,
|
|
19
19
|
([, bs], { buffer }) => buffer!.import(bs),
|
|
20
20
|
([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
|
|
21
|
-
nodes => new List([new Data(html('del', defrag(unwrap(nodes))))]))))
|
|
21
|
+
nodes => new List([new Data(html('del', defrag(unwrap(nodes))))]))));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
|
|
2
2
|
import { Recursion, Command } from '../context';
|
|
3
3
|
import { Result, List, Data, Node, Context, IntermediateParser } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence,
|
|
4
|
+
import { union, some, recursion, precedence, surround, open, lazy, bind } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { strong } from './strong';
|
|
7
7
|
import { emphasis } from './emphasis';
|
|
@@ -24,7 +24,7 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
|
|
|
24
24
|
// 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
|
|
25
25
|
// 可能な限り早く閉じるよう解析しなければならない。
|
|
26
26
|
// このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
|
|
27
|
-
export const emstrong: EmStrongParser = lazy(() =>
|
|
27
|
+
export const emstrong: EmStrongParser = lazy(() =>
|
|
28
28
|
precedence(0, repeat('***', surround(
|
|
29
29
|
'',
|
|
30
30
|
recursion(Recursion.inline,
|
|
@@ -142,7 +142,7 @@ export const emstrong: EmStrongParser = lazy(() => validate('***',
|
|
|
142
142
|
nodes = prepend('*'.repeat(prefix - postfix), nodes);
|
|
143
143
|
}
|
|
144
144
|
return nodes;
|
|
145
|
-
})))
|
|
145
|
+
})));
|
|
146
146
|
|
|
147
147
|
function prepend<N>(prefix: string, nodes: List<Data<N>>): List<Data<N>> {
|
|
148
148
|
if (typeof nodes.head?.value === 'string') {
|
|
@@ -11,7 +11,7 @@ import { html } from 'typed-dom/dom';
|
|
|
11
11
|
// 継続的編集において最も簡便となる。
|
|
12
12
|
|
|
13
13
|
export const indexer: ExtensionParser.IndexerParser = surround(
|
|
14
|
-
|
|
14
|
+
/ \[(?=\|\S)/y,
|
|
15
15
|
union([
|
|
16
16
|
signature,
|
|
17
17
|
focus(/\|(?=\])/y, () => new List([new Data(html('span', { class: 'indexer', 'data-index': '' }))])),
|
|
@@ -65,6 +65,7 @@ describe('Unit: parser/inline/html', () => {
|
|
|
65
65
|
it('basic', () => {
|
|
66
66
|
assert.deepStrictEqual(inspect(parser('<wbr>'), ctx), [['<wbr>'], '']);
|
|
67
67
|
assert.deepStrictEqual(inspect(parser('<wbr >'), ctx), [['<wbr>'], '']);
|
|
68
|
+
assert.deepStrictEqual(inspect(parser('<wbr >'), ctx), [['<span class="invalid"><wbr </span>'], ' >']);
|
|
68
69
|
assert.deepStrictEqual(inspect(parser('<wbr>a'), ctx), [['<wbr>'], 'a']);
|
|
69
70
|
assert.deepStrictEqual(inspect(parser('<bdi >a</bdi>'), ctx), [['<bdi>a</bdi>'], '']);
|
|
70
71
|
assert.deepStrictEqual(inspect(parser('<bdi >a</bdi>'), ctx), [['<span class="invalid"><bdi >a</bdi></span>'], '']);
|
|
@@ -32,7 +32,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
|
|
|
32
32
|
([as, bs = new List()], context) =>
|
|
33
33
|
new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
|
|
34
34
|
match(
|
|
35
|
-
new RegExp(String.raw`<(${TAGS.join('|')})(?=[
|
|
35
|
+
new RegExp(String.raw`<(${TAGS.join('|')})(?=[ >])`, 'y'),
|
|
36
36
|
memoize(
|
|
37
37
|
([, tag]) =>
|
|
38
38
|
surround<HTMLParser.TagParser, string>(
|
|
@@ -13,7 +13,7 @@ describe('Unit: parser/inline/insertion', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('+'), ctx), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('++'), ctx), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('++a'), ctx), [['++', 'a'], '']);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('++a+'), ctx), [['++', 'a
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('++a+'), ctx), [['++', 'a+'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser(' ++a++'), ctx), undefined);
|
|
18
18
|
});
|
|
19
19
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { InsertionParser } from '../inline';
|
|
2
2
|
import { Recursion, Command } from '../context';
|
|
3
3
|
import { List, Data } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence,
|
|
4
|
+
import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { blankWith } from '../visibility';
|
|
7
7
|
import { unwrap, repeat } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
|
-
export const insertion: InsertionParser = lazy(() =>
|
|
10
|
+
export const insertion: InsertionParser = lazy(() =>
|
|
11
11
|
precedence(0, repeat('++', surround(
|
|
12
12
|
'',
|
|
13
13
|
recursion(Recursion.inline,
|
|
@@ -18,4 +18,4 @@ export const insertion: InsertionParser = lazy(() => validate('++',
|
|
|
18
18
|
'++', false,
|
|
19
19
|
([, bs], { buffer }) => buffer!.import(bs),
|
|
20
20
|
([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
|
|
21
|
-
nodes => new List([new Data(html('ins', defrag(unwrap(nodes))))]))))
|
|
21
|
+
nodes => new List([new Data(html('ins', defrag(unwrap(nodes))))]))));
|
|
@@ -16,8 +16,8 @@ describe('Unit: parser/inline/italic', () => {
|
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('///a\n///'), ctx), [['///', 'a', '<br>', '///'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('///a\\ ///'), ctx), [['///', 'a', ' ', '///'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('///a\\\n///'), ctx), [['///', 'a', '<br>', '///'], '']);
|
|
19
|
-
assert.deepStrictEqual(inspect(parser('///a/b'), ctx), [['///', 'a
|
|
20
|
-
assert.deepStrictEqual(inspect(parser('///a//b'), ctx), [['///', 'a
|
|
19
|
+
assert.deepStrictEqual(inspect(parser('///a/b'), ctx), [['///', 'a/b'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser('///a//b'), ctx), [['///', 'a//b'], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('///a*b///'), ctx), [['///', 'a', '*', 'b', '///'], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('/// ///'), ctx), undefined);
|
|
23
23
|
assert.deepStrictEqual(inspect(parser('/// a///'), ctx), undefined);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ItalicParser } from '../inline';
|
|
2
2
|
import { Recursion, Command } from '../context';
|
|
3
3
|
import { List, Data } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence,
|
|
4
|
+
import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { tightStart, blankWith } from '../visibility';
|
|
7
7
|
import { unwrap, repeat } from '../util';
|
|
@@ -10,7 +10,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
10
10
|
// 可読性のため実際にはオブリーク体を指定する。
|
|
11
11
|
// 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
|
|
12
12
|
// ある程度の長さのある文に使うのが望ましい。
|
|
13
|
-
export const italic: ItalicParser = lazy(() =>
|
|
13
|
+
export const italic: ItalicParser = lazy(() =>
|
|
14
14
|
precedence(0, repeat('///', surround(
|
|
15
15
|
'',
|
|
16
16
|
recursion(Recursion.inline,
|
|
@@ -21,4 +21,4 @@ export const italic: ItalicParser = lazy(() => validate('///',
|
|
|
21
21
|
'///', false,
|
|
22
22
|
([, bs], { buffer }) => buffer!.import(bs),
|
|
23
23
|
([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
|
|
24
|
-
nodes => new List([new Data(html('i', defrag(unwrap(nodes))))]))))
|
|
24
|
+
nodes => new List([new Data(html('i', defrag(unwrap(nodes))))]))));
|
|
@@ -180,7 +180,6 @@ describe('Unit: parser/inline/link', () => {
|
|
|
180
180
|
assert.deepStrictEqual(inspect(parser('[[![]{a}]{b}]{b}'), ctx), [['<a class="link" href="b">[![]{a}]{b}</a>'], '']);
|
|
181
181
|
assert.deepStrictEqual(inspect(parser('[((a))]{b}'), ctx), [['<a class="link" href="b"><span class="paren">((a))</span></a>'], '']);
|
|
182
182
|
assert.deepStrictEqual(inspect(parser('[[[a]]]{b}'), ctx), [['<a class="link" href="b">[[a]]</a>'], '']);
|
|
183
|
-
assert.deepStrictEqual(inspect(parser('[!http://host]{/}'), ctx), [['<a class="link" href="/" target="_blank"><img class="media" data-src="http://host" alt="http://host"></a>'], '']);
|
|
184
183
|
assert.deepStrictEqual(inspect(parser('[#a]{b}'), ctx), [['<a class="link" href="b">#a</a>'], '']);
|
|
185
184
|
assert.deepStrictEqual(inspect(parser('[@a]{b}'), ctx), [['<a class="link" href="b">@a</a>'], '']);
|
|
186
185
|
assert.deepStrictEqual(inspect(parser('[@a@b]{c}'), ctx), [['<a class="link" href="c">@a@b</a>'], '']);
|
|
@@ -2,7 +2,7 @@ import { MarkdownParser } from '../../../markdown';
|
|
|
2
2
|
import { LinkParser } from '../inline';
|
|
3
3
|
import { State, Backtrack, Command } from '../context';
|
|
4
4
|
import { List, Data } from '../../combinator/data/parser';
|
|
5
|
-
import { union, inits, tails, sequence, subsequence, some, creation, precedence, state, constraint,
|
|
5
|
+
import { union, inits, tails, sequence, subsequence, some, creation, precedence, state, constraint, surround, open, setBacktrack, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
6
6
|
import { inline, media, shortmedia } from '../inline';
|
|
7
7
|
import { attributes } from './html';
|
|
8
8
|
import { unescsource, str } from '../source';
|
|
@@ -75,7 +75,7 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
|
|
|
75
75
|
return new List([new Data(parse(content, params as List<Data<string>>, context))]);
|
|
76
76
|
}))))));
|
|
77
77
|
|
|
78
|
-
export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State.link | State.media,
|
|
78
|
+
export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State.link | State.media, creation(10,
|
|
79
79
|
state(State.linkers,
|
|
80
80
|
bind(sequence([
|
|
81
81
|
dup(surround(
|
|
@@ -85,7 +85,7 @@ export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State
|
|
|
85
85
|
dup(surround(/{(?![{}])/y, inits([uri, some(option)]), / ?}/y)),
|
|
86
86
|
]),
|
|
87
87
|
([{ value: content }, { value: params }], context) =>
|
|
88
|
-
new List([new Data(parse(content, params as List<Data<string>>, context))]))))))
|
|
88
|
+
new List([new Data(parse(content, params as List<Data<string>>, context))]))))));
|
|
89
89
|
|
|
90
90
|
export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
|
|
91
91
|
creation(10,
|
|
@@ -13,7 +13,7 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('='), ctx), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('=='), ctx), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('==a'), ctx), [['==', 'a'], '']);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('==a='), ctx), [['==', 'a
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('==a='), ctx), [['==', 'a='], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=='], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=='], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('==a\n=='), ctx), [['==', 'a', '<br>', '=='], '']);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { MarkParser } from '../inline';
|
|
2
2
|
import { State, Recursion, Command } from '../context';
|
|
3
3
|
import { List, Data } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence, state, constraint,
|
|
4
|
+
import { union, some, recursion, precedence, state, constraint, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { identity, signature } from './extension/indexee';
|
|
7
7
|
import { tightStart, blankWith } from '../visibility';
|
|
8
8
|
import { unwrap, repeat } from '../util';
|
|
9
9
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
|
-
export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mark,
|
|
11
|
+
export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mark,
|
|
12
12
|
precedence(0, state(State.mark, repeat('==', surround(
|
|
13
13
|
'',
|
|
14
14
|
recursion(Recursion.inline,
|
|
@@ -25,4 +25,4 @@ export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mar
|
|
|
25
25
|
return el.id
|
|
26
26
|
? new List([new Data(el), new Data(html('a', { href: `#${el.id}` }))])
|
|
27
27
|
: new List([new Data(el)]);
|
|
28
|
-
})))))
|
|
28
|
+
})))));
|
|
@@ -8,9 +8,9 @@ import { unwrap, invalid } from '../util';
|
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
export const remark: RemarkParser = lazy(() => fallback(surround(
|
|
11
|
-
str(/\[%(
|
|
11
|
+
str(/\[%(?=[ \n])/y),
|
|
12
12
|
precedence(3, recursion(Recursion.inline,
|
|
13
|
-
some(union([inline]),
|
|
13
|
+
some(union([inline]), /[ \n]%\]/y, [[/[ \n]%\]/y, 3]]))),
|
|
14
14
|
close(text, str(`%]`)), true,
|
|
15
15
|
([as, bs = new List(), cs]) => new List([
|
|
16
16
|
new Data(html('span', { class: 'remark' }, [
|
|
@@ -19,6 +19,6 @@ export const remark: RemarkParser = lazy(() => fallback(surround(
|
|
|
19
19
|
])),
|
|
20
20
|
]),
|
|
21
21
|
([as, bs]) => bs && as.import(bs as List<Data<string>>)),
|
|
22
|
-
focus(/\[%+(
|
|
22
|
+
focus(/\[%+(?=[ \n])/y, ({ context: { source } }) => new List([
|
|
23
23
|
new Data(html('span', { class: 'invalid', ...invalid('remark', 'syntax', 'Invalid start symbol') }, source))
|
|
24
24
|
]))));
|
|
@@ -165,19 +165,19 @@ describe('Unit: parser/inline', () => {
|
|
|
165
165
|
assert.deepStrictEqual(inspect(parser('"[% *"*"*'), ctx), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
|
|
166
166
|
assert.deepStrictEqual(inspect(parser('"[% "*"* %]'), ctx), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
|
|
167
167
|
assert.deepStrictEqual(inspect(parser('"{{""}}'), ctx), [['"', '{', '{', '"', '"', '}', '}'], '']);
|
|
168
|
-
assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(<bdi>)">http://host
|
|
169
|
-
assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host
|
|
168
|
+
assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(<bdi>)">http://host/<span class="paren">(<span class="invalid"><bdi></span>)</span></a>', '</bdi', '>'], '']);
|
|
169
|
+
assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host/<span class="paren">(<span class="invalid"><bdi></span>)</span></a>', '</bdi', '>'], '']);
|
|
170
170
|
assert.deepStrictEqual(inspect(parser('[#a|<bdi>]</bdi>'), ctx), [['<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
171
171
|
assert.deepStrictEqual(inspect(parser('[[#a|<bdi>]</bdi>'), ctx), [['[', '<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it('uri', () => {
|
|
175
175
|
assert.deepStrictEqual(inspect(parser('\nhttp://host'), ctx), [['<br>', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
176
|
-
assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http
|
|
177
|
-
assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp
|
|
176
|
+
assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http', '://host'], '']);
|
|
177
|
+
assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp', '://host'], '']);
|
|
178
178
|
assert.deepStrictEqual(inspect(parser('?http://host'), ctx), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
179
179
|
assert.deepStrictEqual(inspect(parser('0!http://host'), ctx), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
180
|
-
assert.deepStrictEqual(inspect(parser('0?http://host'), ctx), [['0
|
|
180
|
+
assert.deepStrictEqual(inspect(parser('0?http://host'), ctx), [['0?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
181
181
|
assert.deepStrictEqual(inspect(parser('_http://host'), ctx), [['_', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
182
182
|
assert.deepStrictEqual(inspect(parser('_http://host_'), ctx), [['_', '<a class="url" href="http://host" target="_blank">http://host</a>', '_'], '']);
|
|
183
183
|
assert.deepStrictEqual(inspect(parser('*http://host*'), ctx), [['<em><a class="url" href="http://host" target="_blank">http://host</a></em>'], '']);
|
|
@@ -210,7 +210,7 @@ describe('Unit: parser/inline', () => {
|
|
|
210
210
|
|
|
211
211
|
it('account', () => {
|
|
212
212
|
assert.deepStrictEqual(inspect(parser('@a'), ctx), [['<a class="account" href="/@a">@a</a>'], '']);
|
|
213
|
-
assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http', '://host'], '']);
|
|
213
|
+
assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@', 'http', '://host'], '']);
|
|
214
214
|
assert.deepStrictEqual(inspect(parser('_@a'), ctx), [['_', '<a class="account" href="/@a">@a</a>'], '']);
|
|
215
215
|
assert.deepStrictEqual(inspect(parser('_@a_'), ctx), [['_', '<a class="account" href="/@a">@a</a>', '_'], '']);
|
|
216
216
|
assert.deepStrictEqual(inspect(parser('*@a*'), ctx), [['<em><a class="account" href="/@a">@a</a></em>'], '']);
|
|
@@ -222,9 +222,9 @@ describe('Unit: parser/inline', () => {
|
|
|
222
222
|
assert.deepStrictEqual(inspect(parser('#a#'), ctx), [['#a', '#'], '']);
|
|
223
223
|
assert.deepStrictEqual(inspect(parser('#a#b'), ctx), [['#a', '#b'], '']);
|
|
224
224
|
assert.deepStrictEqual(inspect(parser('#a'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
225
|
-
assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#http', '://host'], '']);
|
|
225
|
+
assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#', 'http', '://host'], '']);
|
|
226
226
|
assert.deepStrictEqual(inspect(parser('#a\nb\n#c\n[#d]'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>', '<br>', 'b', '<br>', '<a class="hashtag" href="/hashtags/c">#c</a>', '<br>', '<a class="index" href="#index::d">d</a>'], '']);
|
|
227
|
-
assert.deepStrictEqual(inspect(parser('##a'), ctx), [['
|
|
227
|
+
assert.deepStrictEqual(inspect(parser('##a'), ctx), [['#', '<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
228
228
|
assert.deepStrictEqual(inspect(parser('_#a'), ctx), [['_', '<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
229
229
|
assert.deepStrictEqual(inspect(parser('_#a_'), ctx), [['_', '<a class="hashtag" href="/hashtags/a">#a</a>', '_'], '']);
|
|
230
230
|
assert.deepStrictEqual(inspect(parser('_#a_b'), ctx), [['_', '<a class="hashtag" href="/hashtags/a_b">#a_b</a>'], '']);
|
|
@@ -233,8 +233,8 @@ describe('Unit: parser/inline', () => {
|
|
|
233
233
|
assert.deepStrictEqual(inspect(parser('0a#b'), ctx), [['0a', '#b'], '']);
|
|
234
234
|
assert.deepStrictEqual(inspect(parser('あ#b'), ctx), [['あ', '#b'], '']);
|
|
235
235
|
assert.deepStrictEqual(inspect(parser('あい#b'), ctx), [['あい', '#b'], '']);
|
|
236
|
-
assert.deepStrictEqual(inspect(parser('0aあ#b'), ctx), [['0a
|
|
237
|
-
assert.deepStrictEqual(inspect(parser('0aあい#b'), ctx), [['0a
|
|
236
|
+
assert.deepStrictEqual(inspect(parser('0aあ#b'), ctx), [['0aあ', '#b'], '']);
|
|
237
|
+
assert.deepStrictEqual(inspect(parser('0aあい#b'), ctx), [['0aあい', '#b'], '']);
|
|
238
238
|
assert.deepStrictEqual(inspect(parser('「#あ」'), ctx), [['「', '<a class="hashtag" href="/hashtags/あ">#あ</a>', '」'], '']);
|
|
239
239
|
assert.deepStrictEqual(inspect(parser('a\n#b'), ctx), [['a', '<br>', '<a class="hashtag" href="/hashtags/b">#b</a>'], '']);
|
|
240
240
|
assert.deepStrictEqual(inspect(parser('a\\\n#b'), ctx), [['a', '<br>', '<a class="hashtag" href="/hashtags/b">#b</a>'], '']);
|
|
@@ -248,7 +248,7 @@ describe('Unit: parser/inline', () => {
|
|
|
248
248
|
it('hashnum', () => {
|
|
249
249
|
assert.deepStrictEqual(inspect(parser('#1'), ctx), [['<a class="hashnum">#1</a>'], '']);
|
|
250
250
|
assert.deepStrictEqual(inspect(parser(`#1'`), ctx), [[`<a class="hashnum">#1</a>`, `'`], '']);
|
|
251
|
-
assert.deepStrictEqual(inspect(parser('#1234567890@a'), ctx), [['#1234567890', '@a'], '']);
|
|
251
|
+
assert.deepStrictEqual(inspect(parser('#1234567890@a'), ctx), [['#', '1234567890', '@a'], '']);
|
|
252
252
|
assert.deepStrictEqual(inspect(parser('_#1'), ctx), [['_', '<a class="hashnum">#1</a>'], '']);
|
|
253
253
|
assert.deepStrictEqual(inspect(parser('_#1_'), ctx), [['_', '<a class="hashnum">#1</a>', '_'], '']);
|
|
254
254
|
assert.deepStrictEqual(inspect(parser('_#1_0'), ctx), [['_', '<a class="hashtag" href="/hashtags/1_0">#1_0</a>'], '']);
|
package/src/parser/inline.ts
CHANGED
|
@@ -66,6 +66,7 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
66
66
|
case '%':
|
|
67
67
|
return remark(input)
|
|
68
68
|
|| textlink(input)
|
|
69
|
+
|| ruby(input)
|
|
69
70
|
|| bracket(input);
|
|
70
71
|
case '#':
|
|
71
72
|
case '$':
|
|
@@ -74,6 +75,7 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
74
75
|
case '|':
|
|
75
76
|
return extension(input)
|
|
76
77
|
|| textlink(input)
|
|
78
|
+
|| ruby(input)
|
|
77
79
|
|| bracket(input);
|
|
78
80
|
}
|
|
79
81
|
return textlink(input)
|
|
@@ -103,7 +103,6 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
|
|
|
103
103
|
const char = source[index];
|
|
104
104
|
switch (char) {
|
|
105
105
|
case '$':
|
|
106
|
-
case '%':
|
|
107
106
|
case '*':
|
|
108
107
|
case '+':
|
|
109
108
|
case '~':
|
|
@@ -111,10 +110,15 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
|
|
|
111
110
|
case '/':
|
|
112
111
|
index = backToWhitespace(source, position, index);
|
|
113
112
|
break;
|
|
113
|
+
case '%':
|
|
114
|
+
index += index - 1 > position && source.startsWith(' %]', index - 1)
|
|
115
|
+
? -1
|
|
116
|
+
: 0;
|
|
117
|
+
break;
|
|
114
118
|
case '[':
|
|
115
|
-
index
|
|
116
|
-
?
|
|
117
|
-
:
|
|
119
|
+
index += index - 1 > position && source.startsWith(' [|', index - 1)
|
|
120
|
+
? -1
|
|
121
|
+
: 0;
|
|
118
122
|
break;
|
|
119
123
|
case ':':
|
|
120
124
|
index = source.startsWith('//', index + 1)
|
package/src/parser/util.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function repeat<N extends HTMLElement | string>(symbol: string, parser: P
|
|
|
28
28
|
return failsafe(input => {
|
|
29
29
|
const { context } = input;
|
|
30
30
|
const { source, position } = context;
|
|
31
|
-
|
|
31
|
+
if (!source.startsWith(symbol, context.position)) return;
|
|
32
32
|
let nodes = new List<Data<N>>();
|
|
33
33
|
let i = symbol.length;
|
|
34
34
|
for (; source[context.position + i] === source[context.position];) ++i;
|
package/src/parser/visibility.ts
CHANGED
|
@@ -8,11 +8,11 @@ import { invisibleHTMLEntityNames } from './api/normalize';
|
|
|
8
8
|
export namespace blank {
|
|
9
9
|
export const line = new RegExp(
|
|
10
10
|
// TODO: 行全体をエスケープ
|
|
11
|
-
/^(
|
|
11
|
+
/^(\\?[^\S\r\n]|&IHN;|<wbr ?>|\\$)+$/mg.source
|
|
12
12
|
.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
13
13
|
'gm');
|
|
14
14
|
export const start = new RegExp(
|
|
15
|
-
/(?:\\?[^\S\r\n]|&IHN;|<wbr
|
|
15
|
+
/(?:\\?[^\S\r\n]|&IHN;|<wbr ?>)+/y.source
|
|
16
16
|
.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`), 'y');
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -46,7 +46,7 @@ export function blankWith(starts: '' | '\n', delimiter: string | RegExp): RegExp
|
|
|
46
46
|
export function blankWith(starts: '' | '\n', delimiter?: string | RegExp): RegExp {
|
|
47
47
|
if (delimiter === undefined) return blankWith('', starts);
|
|
48
48
|
return new RegExp(String.raw
|
|
49
|
-
`(?:(?=${starts})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr
|
|
49
|
+
`(?:(?=${starts})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr ?>)${
|
|
50
50
|
// 空行除去
|
|
51
51
|
// 完全な空行はエスケープ済みなので再帰的バックトラックにはならない。
|
|
52
52
|
starts && '+'
|
|
@@ -75,7 +75,6 @@ export function tightStart<N>(parser: Parser<N>, except?: string): Parser<N> {
|
|
|
75
75
|
? parser(input)
|
|
76
76
|
: undefined;
|
|
77
77
|
}
|
|
78
|
-
const wbr = /<wbr[^\S\n]*>/y;
|
|
79
78
|
function isTightStart(input: Input<MarkdownParser.Context>, except?: string): boolean {
|
|
80
79
|
const { context } = input;
|
|
81
80
|
const { source, position } = context;
|
|
@@ -100,11 +99,10 @@ function isTightStart(input: Input<MarkdownParser.Context>, except?: string): bo
|
|
|
100
99
|
context.position = position;
|
|
101
100
|
return true;
|
|
102
101
|
case '<':
|
|
103
|
-
wbr.lastIndex = position;
|
|
104
102
|
switch (true) {
|
|
105
103
|
case source.length - position >= 5
|
|
106
104
|
&& source.startsWith('<wbr', position)
|
|
107
|
-
&& (source[position +
|
|
105
|
+
&& (source[position + 4] === '>' || source.startsWith(' >', position + 4)):
|
|
108
106
|
return false;
|
|
109
107
|
}
|
|
110
108
|
return true;
|