securemark 0.295.5 → 0.295.7

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.
@@ -21,7 +21,7 @@ const opener = /(?=\|\|+(?:$|[ \n]))/y;
21
21
  const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?: |(?=\|*(?:$|[ \n])))|\n$/g, '');
22
22
 
23
23
  const source: SidefenceParser.SourceParser = lazy(() => fmap(
24
- some(recursion(Recursion.block, union([
24
+ recursion(Recursion.block, some(union([
25
25
  focus(
26
26
  /(?:\|\|+(?=$|[ \n])[^\n]*(?:$|\n))+/y,
27
27
  convert(unindent, source, true)),
@@ -15,7 +15,7 @@ export const ulist: UListParser = lazy(() => block(validate(
15
15
 
16
16
  export const ulist_: UListParser = lazy(() => block(fmap(validate(
17
17
  /-(?=$|[ \n])/y,
18
- some(recursion(Recursion.listitem, union([
18
+ recursion(Recursion.listitem, some(union([
19
19
  indexee(fmap(fallback(
20
20
  inits([
21
21
  line(open(/-(?:$|[ \n])/y, subsequence([
@@ -12,7 +12,7 @@ export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
12
12
  precedence(0, some(union([
13
13
  some(unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y),
14
14
  precedence(1, verify(bracket, ns => ns.length > 0)),
15
- ]), undefined, [[/[^\x21-\x7E]|\$/y, 9]])),
15
+ ]), [[/[^\x21-\x7E]|\$/y, 9]])),
16
16
  false,
17
17
  [3 | Backtrack.unescapable]),
18
18
  union([
@@ -8,15 +8,14 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const deletion: DeletionParser = lazy(() =>
11
- precedence(0, repeat('~~', surround(
11
+ precedence(0, recursion(Recursion.inline, repeat('~~', surround(
12
12
  '',
13
- recursion(Recursion.inline,
14
13
  some(union([
15
14
  some(inline, blankWith('\n', '~~')),
16
15
  open('\n', some(inline, '~'), true),
17
- ]))),
16
+ ])),
18
17
  '~~',
19
18
  false, [],
20
19
  ([, bs], { buffer }) => buffer.import(bs),
21
20
  ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
22
- nodes => new List([new Node(html('del', defrag(unwrap(nodes))))]))));
21
+ nodes => new List([new Node(html('del', defrag(unwrap(nodes))))])))));
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/emphasis', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('*', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('*a', new Context())), [['*', 'a'], '']);
14
- assert.deepStrictEqual(inspect(parser, input('*a *', new Context())), [['*', 'a', ' ', '*'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('*a *', new Context())), [['*', 'a ', '*'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('*a *', new Context())), [['*', 'a', ' ', '*'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('*a\n*', new Context())), [['*', 'a', '<br>', '*'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('*a\\ *', new Context())), [['*', 'a', ' ', '*'], '']);
@@ -1,11 +1,11 @@
1
1
  import { EmphasisParser } from '../inline';
2
2
  import { Recursion } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
4
+ import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
7
  import { str } from '../source';
8
- import { tightStart, blankWith } from '../visibility';
8
+ import { tightStart, afterNonblank } from '../visibility';
9
9
  import { unwrap } from '../util';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
@@ -13,9 +13,8 @@ export const emphasis: EmphasisParser = lazy(() => surround(
13
13
  str(/\*(?!\*)/y),
14
14
  precedence(0, recursion(Recursion.inline,
15
15
  tightStart(some(union([
16
+ some(inline, '*', afterNonblank),
16
17
  strong,
17
- some(inline, blankWith('*')),
18
- open(some(inline, '*'), inline),
19
18
  ]))))),
20
19
  str('*'),
21
20
  false, [],
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/emstrong', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('***', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('***a', new Context())), [['***a'], '']);
14
- assert.deepStrictEqual(inspect(parser, input('***a ***', new Context())), [['***a', ' ', '***'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('***a ***', new Context())), [['***a ', '***'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('***a ***', new Context())), [['***a', ' ', '***'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('***a\n***', new Context())), [['***a', '<br>', '***'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('***a\\ ***', new Context())), [['***a', ' ', '***'], '']);
@@ -66,7 +66,7 @@ describe('Unit: parser/inline/emstrong', () => {
66
66
  assert.deepStrictEqual(inspect(parser, input('***a*\\ **b****', new Context())), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
67
67
  assert.deepStrictEqual(inspect(parser, input('***a*&Tab;**b****', new Context())), [['<strong><em>a</em>\t<strong>b</strong></strong>'], '']);
68
68
  assert.deepStrictEqual(inspect(parser, input('***a*<wbr>**b****', new Context())), [['<strong><em>a</em><wbr><strong>b</strong></strong>'], '']);
69
- assert.deepStrictEqual(inspect(parser, input('***a*b **', new Context())), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
69
+ assert.deepStrictEqual(inspect(parser, input('***a*b **', new Context())), [['**', '<em>a</em>', 'b ', '**'], '']);
70
70
  assert.deepStrictEqual(inspect(parser, input('***a*b\\ **', new Context())), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
71
71
  assert.deepStrictEqual(inspect(parser, input('***a**b*', new Context())), [['<em><strong>a</strong>b</em>'], '']);
72
72
  assert.deepStrictEqual(inspect(parser, input('***a**b*c', new Context())), [['<em><strong>a</strong>b</em>'], 'c']);
@@ -77,7 +77,7 @@ describe('Unit: parser/inline/emstrong', () => {
77
77
  assert.deepStrictEqual(inspect(parser, input('***a**\\ *b**', new Context())), [['<em><strong>a</strong> <em>b</em></em>'], '']);
78
78
  assert.deepStrictEqual(inspect(parser, input('***a**&Tab;*b**', new Context())), [['<em><strong>a</strong>\t<em>b</em></em>'], '']);
79
79
  assert.deepStrictEqual(inspect(parser, input('***a**<wbr>*b**', new Context())), [['<em><strong>a</strong><wbr><em>b</em></em>'], '']);
80
- assert.deepStrictEqual(inspect(parser, input('***a**b *', new Context())), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
80
+ assert.deepStrictEqual(inspect(parser, input('***a**b *', new Context())), [['*', '<strong>a</strong>', 'b ', '*'], '']);
81
81
  assert.deepStrictEqual(inspect(parser, input('***a**b\\ *', new Context())), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
82
82
  assert.deepStrictEqual(inspect(parser, input('***a*', new Context())), [['**', '<em>a</em>'], '']);
83
83
  assert.deepStrictEqual(inspect(parser, input('***a**', new Context())), [['*', '<strong>a</strong>'], '']);
@@ -109,11 +109,11 @@ describe('Unit: parser/inline/emstrong', () => {
109
109
  assert.deepStrictEqual(inspect(parser, input('******a******', new Context())), [['<em><strong><em><strong>a</strong></em></strong></em>'], '']);
110
110
  assert.deepStrictEqual(inspect(parser, input('******a******b', new Context())), [['<em><strong><em><strong>a</strong></em></strong></em>'], 'b']);
111
111
  assert.deepStrictEqual(inspect(parser, input('******a*b', new Context())), [['*****', '<em>a</em>', 'b'], '']);
112
- assert.deepStrictEqual(inspect(parser, input('******a*b *', new Context())), [['*****', '<em>a</em>', 'b', ' ', '*'], '']);
113
- assert.deepStrictEqual(inspect(parser, input('******a*b **', new Context())), [['*****', '<em>a</em>', 'b', ' ', '**'], '']);
114
- assert.deepStrictEqual(inspect(parser, input('******a*b ***', new Context())), [['*****', '<em>a</em>', 'b', ' ', '***'], '']);
115
- assert.deepStrictEqual(inspect(parser, input('******a*b ****', new Context())), [['*****', '<em>a</em>', 'b', ' ', '****'], '']);
116
- assert.deepStrictEqual(inspect(parser, input('******a*b *****', new Context())), [['*****', '<em>a</em>', 'b', ' ', '*****'], '']);
112
+ assert.deepStrictEqual(inspect(parser, input('******a*b *', new Context())), [['*****', '<em>a</em>', 'b ', '*'], '']);
113
+ assert.deepStrictEqual(inspect(parser, input('******a*b **', new Context())), [['*****', '<em>a</em>', 'b ', '**'], '']);
114
+ assert.deepStrictEqual(inspect(parser, input('******a*b ***', new Context())), [['*****', '<em>a</em>', 'b ', '***'], '']);
115
+ assert.deepStrictEqual(inspect(parser, input('******a*b ****', new Context())), [['*****', '<em>a</em>', 'b ', '****'], '']);
116
+ assert.deepStrictEqual(inspect(parser, input('******a*b *****', new Context())), [['*****', '<em>a</em>', 'b ', '*****'], '']);
117
117
  });
118
118
 
119
119
  });
@@ -1,37 +1,31 @@
1
1
  import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
2
2
  import { Recursion, Command } from '../context';
3
3
  import { Parser, Result, List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, surround, open, lazy, bind } from '../../combinator';
4
+ import { union, some, recursion, precedence, surround, lazy, bind } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
7
  import { emphasis } from './emphasis';
8
8
  import { str } from '../source';
9
- import { tightStart, blankWith } from '../visibility';
9
+ import { tightStart, afterNonblank } from '../visibility';
10
10
  import { unwrap, repeat } from '../util';
11
11
  import { html, defrag } from 'typed-dom/dom';
12
12
 
13
13
  const substrong: Parser.IntermediateParser<StrongParser> = lazy(() => some(union([
14
+ some(inline, '*', afterNonblank),
14
15
  emphasis,
15
- some(inline, blankWith('*')),
16
- open(some(inline, '*'), inline),
17
16
  ])));
18
17
  const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(union([
18
+ some(inline, '*', afterNonblank),
19
19
  strong,
20
- some(inline, blankWith('*')),
21
- open(some(inline, '*'), inline),
22
20
  ])));
23
21
 
24
22
  // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
25
23
  // 可能な限り早く閉じるよう解析しなければならない。
26
24
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
27
25
  export const emstrong: EmStrongParser = lazy(() =>
28
- precedence(0, repeat('***', surround(
26
+ precedence(0, recursion(Recursion.inline, repeat('***', surround(
29
27
  '',
30
- recursion(Recursion.inline,
31
- tightStart(some(union([
32
- some(inline, blankWith('*')),
33
- open(some(inline, '*'), inline),
34
- ])))),
28
+ tightStart(some(union([some(inline, '*', afterNonblank)]))),
35
29
  str(/\*{1,3}/y),
36
30
  false, [],
37
31
  ([, bs, cs], context): Result<Parser.Node<EmStrongParser>, Parser.Context<EmStrongParser>> => {
@@ -143,7 +137,7 @@ export const emstrong: EmStrongParser = lazy(() =>
143
137
  nodes = prepend('*'.repeat(prefix - postfix), nodes);
144
138
  }
145
139
  return nodes;
146
- })));
140
+ }))));
147
141
 
148
142
  function prepend<N>(prefix: string, nodes: List<Node<N>>): List<Node<N>> {
149
143
  if (typeof nodes.head?.value === 'string') {
@@ -8,15 +8,14 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() =>
11
- precedence(0, repeat('++', surround(
11
+ precedence(0, recursion(Recursion.inline, repeat('++', surround(
12
12
  '',
13
- recursion(Recursion.inline,
14
13
  some(union([
15
14
  some(inline, blankWith('\n', '++')),
16
15
  open('\n', some(inline, '+'), true),
17
- ]))),
16
+ ])),
18
17
  '++',
19
18
  false, [],
20
19
  ([, bs], { buffer }) => buffer.import(bs),
21
20
  ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
22
- nodes => new List([new Node(html('ins', defrag(unwrap(nodes))))]))));
21
+ nodes => new List([new Node(html('ins', defrag(unwrap(nodes))))])))));
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/italic', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('///', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('///a', new Context())), [['///', 'a'], '']);
14
- assert.deepStrictEqual(inspect(parser, input('///a ///', new Context())), [['///', 'a', ' ', '///'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('///a ///', new Context())), [['///', 'a ', '///'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('///a ///', new Context())), [['///', 'a', ' ', '///'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('///a\n///', new Context())), [['///', 'a', '<br>', '///'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('///a\\ ///', new Context())), [['///', 'a', ' ', '///'], '']);
@@ -1,9 +1,9 @@
1
1
  import { ItalicParser } from '../inline';
2
2
  import { Recursion, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
4
+ import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
- import { tightStart, blankWith } from '../visibility';
6
+ import { tightStart, afterNonblank } from '../visibility';
7
7
  import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
@@ -11,15 +11,11 @@ import { html, defrag } from 'typed-dom/dom';
11
11
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
12
12
  // ある程度の長さのある文に使うのが望ましい。
13
13
  export const italic: ItalicParser = lazy(() =>
14
- precedence(0, repeat('///', surround(
14
+ precedence(0, recursion(Recursion.inline, repeat('///', surround(
15
15
  '',
16
- recursion(Recursion.inline,
17
- tightStart(some(union([
18
- some(inline, blankWith('///')),
19
- open(some(inline, '/'), inline),
20
- ])))),
16
+ tightStart(some(union([inline]), '///', afterNonblank)),
21
17
  '///',
22
18
  false, [],
23
19
  ([, bs], { buffer }) => buffer.import(bs),
24
20
  ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
25
- nodes => new List([new Node(html('i', defrag(unwrap(nodes))))]))));
21
+ nodes => new List([new Node(html('i', defrag(unwrap(nodes))))])))));
@@ -183,7 +183,7 @@ describe('Unit: parser/inline/link', () => {
183
183
  assert.deepStrictEqual(inspect(parser, input('[@a]{b}', new Context())), [['<a class="link" href="b">@a</a>'], '']);
184
184
  assert.deepStrictEqual(inspect(parser, input('[@a@b]{c}', new Context())), [['<a class="link" href="c">@a@b</a>'], '']);
185
185
  assert.deepStrictEqual(inspect(parser, input('[a@b]{c}', new Context())), [['<a class="link" href="c">a@b</a>'], '']);
186
- assert.deepStrictEqual(inspect(parser, input('[==a==]{b}', new Context())), [['<a class="link" href="b">==a==</a>'], '']);
186
+ assert.deepStrictEqual(inspect(parser, input('[==a==]{b}', new Context())), [['<a class="link" href="b"><mark>a</mark></a>'], '']);
187
187
  assert.deepStrictEqual(inspect(parser, input('[*a*]{b}', new Context())), [['<a class="link" href="b"><em>a</em></a>'], '']);
188
188
  });
189
189
 
@@ -14,7 +14,7 @@ describe('Unit: parser/inline/mark', () => {
14
14
  assert.deepStrictEqual(inspect(parser, input('==', new Context())), undefined);
15
15
  assert.deepStrictEqual(inspect(parser, input('==a', new Context())), [['==', 'a'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('==a=', new Context())), [['==', 'a='], '']);
17
- assert.deepStrictEqual(inspect(parser, input('==a ==', new Context())), [['==', 'a', ' ', '=='], '']);
17
+ assert.deepStrictEqual(inspect(parser, input('==a ==', new Context())), [['==', 'a ', '=='], '']);
18
18
  assert.deepStrictEqual(inspect(parser, input('==a ==', new Context())), [['==', 'a', ' ', '=='], '']);
19
19
  assert.deepStrictEqual(inspect(parser, input('==a\n==', new Context())), [['==', 'a', '<br>', '=='], '']);
20
20
  assert.deepStrictEqual(inspect(parser, input('==a\\ ==', new Context())), [['==', 'a', ' ', '=='], '']);
@@ -38,12 +38,12 @@ describe('Unit: parser/inline/mark', () => {
38
38
  });
39
39
 
40
40
  it('nest', () => {
41
- assert.deepStrictEqual(inspect(parser, input('==a ==b====', new Context())), [['<mark id="mark::a_b">a <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
42
- assert.deepStrictEqual(inspect(parser, input('==- ==b====', new Context())), [['<mark id="mark::-_b">- <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::-_b"></a>'], '']);
43
- assert.deepStrictEqual(inspect(parser, input('==a\\ ==b====', new Context())), [['<mark id="mark::a_b">a <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
44
- assert.deepStrictEqual(inspect(parser, input('==a&Tab;==b====', new Context())), [['<mark id="mark::a_b=33Mw2l">a\t<mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b=33Mw2l"></a>'], '']);
45
- assert.deepStrictEqual(inspect(parser, input('==a<wbr>==b====', new Context())), [['<mark id="mark::ab">a<wbr><mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::ab"></a>'], '']);
46
- assert.deepStrictEqual(inspect(parser, input('==*==a==*==', new Context())), [['<mark id="mark::a"><em><mark id="mark::a">a</mark><a href="#mark::a"></a></em></mark>', '<a href="#mark::a"></a>'], '']);
41
+ assert.deepStrictEqual(inspect(parser, input('==a ==b====', new Context())), [['<mark id="mark::a_b">a <mark>b</mark></mark>', '<a href="#mark::a_b"></a>'], '']);
42
+ assert.deepStrictEqual(inspect(parser, input('==- ==b====', new Context())), [['<mark id="mark::-_b">- <mark>b</mark></mark>', '<a href="#mark::-_b"></a>'], '']);
43
+ assert.deepStrictEqual(inspect(parser, input('==a\\ ==b====', new Context())), [['<mark id="mark::a_b">a <mark>b</mark></mark>', '<a href="#mark::a_b"></a>'], '']);
44
+ assert.deepStrictEqual(inspect(parser, input('==a&Tab;==b====', new Context())), [['<mark id="mark::a_b=33Mw2l">a\t<mark>b</mark></mark>', '<a href="#mark::a_b=33Mw2l"></a>'], '']);
45
+ assert.deepStrictEqual(inspect(parser, input('==a<wbr>==b====', new Context())), [['<mark id="mark::ab">a<wbr><mark>b</mark></mark>', '<a href="#mark::ab"></a>'], '']);
46
+ assert.deepStrictEqual(inspect(parser, input('==*==a==*==', new Context())), [['<mark id="mark::a"><em><mark>a</mark></em></mark>', '<a href="#mark::a"></a>'], '']);
47
47
  });
48
48
 
49
49
  });
@@ -1,29 +1,26 @@
1
1
  import { MarkParser } from '../inline';
2
2
  import { State, Recursion, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, state, constraint, surround, open, lazy } from '../../combinator';
4
+ import { union, some, recursion, precedence, state, surround, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { identity, signature } from './extension/indexee';
7
- import { tightStart, blankWith } from '../visibility';
7
+ import { tightStart, afterNonblank } 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,
12
- precedence(0, state(State.mark, repeat('==', surround(
11
+ export const mark: MarkParser = lazy(() =>
12
+ precedence(0, recursion(Recursion.inline, repeat('==', surround(
13
13
  '',
14
- recursion(Recursion.inline,
15
- tightStart(some(union([
16
- some(inline, blankWith('==')),
17
- open(some(inline, '='), inline),
18
- ])))),
14
+ tightStart(state(State.mark, some(union([inline]), '==', afterNonblank))),
19
15
  '==',
20
16
  false, [],
21
17
  ([, bs], { buffer }) => buffer.import(bs),
22
18
  ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
23
- (nodes, { id }) => {
19
+ (nodes, { id, state }) => {
24
20
  const el = html('mark', defrag(unwrap(nodes)));
21
+ if (state & State.linkers) return new List([new Node(el)]);
25
22
  define(el, { id: identity('mark', id, signature(el)) });
26
23
  return el.id
27
24
  ? new List([new Node(el), new Node(html('a', { href: `#${el.id}` }))])
28
25
  : new List([new Node(el)]);
29
- })))));
26
+ }))));
@@ -109,6 +109,7 @@ describe('Unit: parser/inline/math', () => {
109
109
  assert.deepStrictEqual(inspect(parser, input('$a$[A](a)', new Context())), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '[A](a)']);
110
110
  assert.deepStrictEqual(inspect(parser, input('$A$', new Context())), [['<span class="math" translate="no" data-src="$A$">$A$</span>'], '']);
111
111
  assert.deepStrictEqual(inspect(parser, input('$-a$', new Context())), [['<span class="math" translate="no" data-src="$-a$">$-a$</span>'], '']);
112
+ assert.deepStrictEqual(inspect(parser, input('$\\ $', new Context())), [['<span class="math" translate="no" data-src="$\\ $">$\\ $</span>'], '']);
112
113
  assert.deepStrictEqual(inspect(parser, input('$\\$$', new Context())), [['<span class="math" translate="no" data-src="$\\$$">$\\$$</span>'], '']);
113
114
  assert.deepStrictEqual(inspect(parser, input('$\\Pi$', new Context())), [['<span class="math" translate="no" data-src="$\\Pi$">$\\Pi$</span>'], '']);
114
115
  assert.deepStrictEqual(inspect(parser, input('$\\ 0$', new Context())), [['<span class="math" translate="no" data-src="$\\ 0$">$\\ 0$</span>'], '']);
@@ -30,8 +30,8 @@ describe('Unit: parser/inline/remark', () => {
30
30
  assert.deepStrictEqual(inspect(parser, input('[%% a [% b', new Context())), [['<span class="invalid">[%%</span>'], ' a [% b']);
31
31
  assert.deepStrictEqual(inspect(parser, input('[%\\ a %]', new Context())), undefined);
32
32
  assert.deepStrictEqual(inspect(parser, input('[% a\\ %]', new Context())), [['[%', ' a', ' ', '%', ']'], '']);
33
- assert.deepStrictEqual(inspect(parser, input('[% a%]', new Context())), [['[%', ' a', '%', ']'], '']);
34
- assert.deepStrictEqual(inspect(parser, input('[% a %%]', new Context())), [['[%', ' a %', '%', ']'], '']);
33
+ assert.deepStrictEqual(inspect(parser, input('[% a%]', new Context())), [['[%', ' a%', ']'], '']);
34
+ assert.deepStrictEqual(inspect(parser, input('[% a %%]', new Context())), [['[%', ' a %%', ']'], '']);
35
35
  assert.deepStrictEqual(inspect(parser, input('[% [%% %]', new Context())), [['<span class="remark"><input type="checkbox"><span>[% <span class="invalid">[%%</span> %]</span></span>'], '']);
36
36
  assert.deepStrictEqual(inspect(parser, input('[%% [% %%]', new Context())), [['<span class="invalid">[%%</span>'], ' [% %%]']);
37
37
  assert.deepStrictEqual(inspect(parser, input('[%% a %]', new Context())), [['<span class="invalid">[%%</span>'], ' a %]']);
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/strong', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('**', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('**a', new Context())), [['**', 'a'], '']);
14
- assert.deepStrictEqual(inspect(parser, input('**a **', new Context())), [['**', 'a', ' ', '**'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('**a **', new Context())), [['**', 'a ', '**'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('**a **', new Context())), [['**', 'a', ' ', '**'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('**a\n**', new Context())), [['**', 'a', '<br>', '**'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('**a\\ **', new Context())), [['**', 'a', ' ', '**'], '']);
@@ -1,11 +1,11 @@
1
1
  import { StrongParser } from '../inline';
2
2
  import { Recursion } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
4
+ import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { emphasis } from './emphasis';
7
7
  import { str } from '../source';
8
- import { tightStart, blankWith } from '../visibility';
8
+ import { tightStart, afterNonblank } from '../visibility';
9
9
  import { unwrap } from '../util';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
@@ -13,9 +13,8 @@ export const strong: StrongParser = lazy(() => surround(
13
13
  str(/\*\*(?!\*)/y),
14
14
  precedence(0, recursion(Recursion.inline,
15
15
  tightStart(some(union([
16
+ some(inline, '*', afterNonblank),
16
17
  emphasis,
17
- some(inline, blankWith('*')),
18
- open(some(inline, '*'), inline),
19
18
  ]))))),
20
19
  str('**'),
21
20
  false, [],
@@ -40,7 +40,7 @@ describe('Unit: parser/inline', () => {
40
40
  assert.deepStrictEqual(inspect(parser, input('*a***b****', new Context())), [['<em>a</em>', '<strong>b</strong>', '**'], '']);
41
41
  assert.deepStrictEqual(inspect(parser, input('*a***b****c', new Context())), [['<em>a</em>', '<strong>b</strong>', '**', 'c'], '']);
42
42
  assert.deepStrictEqual(inspect(parser, input('*a *b**', new Context())), [['<em>a <em>b</em></em>'], '']);
43
- assert.deepStrictEqual(inspect(parser, input('*a *b**c', new Context())), [['*', 'a', ' ', '*', 'b', '**', 'c'], '']);
43
+ assert.deepStrictEqual(inspect(parser, input('*a *b**c', new Context())), [['*', 'a ', '*', 'b', '**', 'c'], '']);
44
44
  assert.deepStrictEqual(inspect(parser, input('*a **b***', new Context())), [['<em>a <strong>b</strong></em>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser, input('*a **b***c', new Context())), [['<em>a <strong>b</strong></em>', 'c'], '']);
46
46
  assert.deepStrictEqual(inspect(parser, input('*a ***b****', new Context())), [['<em>a <em><strong>b</strong></em></em>'], '']);
@@ -101,8 +101,8 @@ describe('Unit: parser/inline', () => {
101
101
  assert.deepStrictEqual(inspect(parser, input('[$1]', new Context())), [['[', '$1', ']'], '']);
102
102
  assert.deepStrictEqual(inspect(parser, input('[$1-2]', new Context())), [['[', '$1-2', ']'], '']);
103
103
  assert.deepStrictEqual(inspect(parser, input('[$-1][$-2]', new Context())), [['<a class="label" data-label="$-1">$-1</a>', '<a class="label" data-label="$-2">$-2</a>'], '']);
104
- assert.deepStrictEqual(inspect(parser, input('$-1, $-2', new Context())), [['<a class="label" data-label="$-1">$-1</a>', ',', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
105
- assert.deepStrictEqual(inspect(parser, input('$-1 and $-2', new Context())), [['<a class="label" data-label="$-1">$-1</a>', ' and', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
104
+ assert.deepStrictEqual(inspect(parser, input('$-1, $-2', new Context())), [['<a class="label" data-label="$-1">$-1</a>', ', ', '<a class="label" data-label="$-2">$-2</a>'], '']);
105
+ assert.deepStrictEqual(inspect(parser, input('$-1 and $-2', new Context())), [['<a class="label" data-label="$-1">$-1</a>', ' and ', '<a class="label" data-label="$-2">$-2</a>'], '']);
106
106
  assert.deepStrictEqual(inspect(parser, input('$$-1', new Context())), [['$', '<a class="label" data-label="$-1">$-1</a>'], '']);
107
107
  assert.deepStrictEqual(inspect(parser, input('[[#a]]', new Context())), [['<sup class="reference"><span><a class="hashtag" href="/hashtags/a">#a</a></span></sup>'], '']);
108
108
  assert.deepStrictEqual(inspect(parser, input('[[$-1]]', new Context())), [['<sup class="reference"><span><a class="label" data-label="$-1">$-1</a></span></sup>'], '']);
@@ -154,7 +154,7 @@ describe('Unit: parser/inline', () => {
154
154
  assert.deepStrictEqual(inspect(parser, input('[[a\nb]]', new Context())), [['[', '[', 'a', '<br>', 'b', ']', ']'], '']);
155
155
  assert.deepStrictEqual(inspect(parser, input('[[[a\nb]]]', new Context())), [['[', '[', '[', 'a', '<br>', 'b', ']', ']', ']'], '']);
156
156
  assert.deepStrictEqual(inspect(parser, input('"[[""]]', new Context())), [['"', '[', '[', '"', '"', ']', ']'], '']);
157
- assert.deepStrictEqual(inspect(parser, input('[==a==]{b}', new Context())), [['<a class="link" href="b">==a==</a>'], '']);
157
+ assert.deepStrictEqual(inspect(parser, input('[==a==]{b}', new Context())), [['<a class="link" href="b"><mark>a</mark></a>'], '']);
158
158
  assert.deepStrictEqual(inspect(parser, input('[[a](b)]{c}', new Context())), [['<a class="link" href="c"><ruby>a<rp>(</rp><rt>b</rt><rp>)</rp></ruby></a>'], '']);
159
159
  assert.deepStrictEqual(inspect(parser, input('[[[[[[[{a}', new Context())), [['[', '[', '[', '[', '[', '[', '[', '<a class="url" href="a">a</a>'], '']);
160
160
  assert.deepStrictEqual(inspect(parser, input('<http://host>', new Context())), [['<', '<a class="url" href="http://host" target="_blank">http://host</a>', '>'], '']);
@@ -170,6 +170,7 @@ describe('Unit: parser/inline', () => {
170
170
  assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(&lt;bdi&gt;)">@a/http://host/<span class="paren">(<span class="invalid">&lt;bdi&gt;</span>)</span></a>', '</bdi', '>'], '']);
171
171
  assert.deepStrictEqual(inspect(parser, input('[#a|<bdi>]</bdi>', new Context())), [['<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
172
172
  assert.deepStrictEqual(inspect(parser, input('[[#a|<bdi>]</bdi>', new Context())), [['[', '<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
173
+ assert.deepStrictEqual(inspect(parser, input('[*==*]{a}', new Context())), [['<a class="link" href="a">*==*</a>'], '']);
173
174
  assert.deepStrictEqual(inspect(parser, input('[]{"}[[""]]}]', new Context())), [['<a class="url" href="&quot;">"</a>', '<sup class="reference"><span>""</span></sup>', '}', ']'], '']);
174
175
  assert.deepStrictEqual(inspect(parser, input('[ []{"}[[""]]}]', new Context())), [['[', ' ', '<a class="url" href="&quot;">"</a>', '<sup class="reference"><span>""</span></sup>', '}', ']'], '']);
175
176
  });
@@ -8,7 +8,7 @@ import { html } from 'typed-dom/dom';
8
8
  const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
9
9
 
10
10
  export const escsource: EscapableSourceParser = ({ context }) => {
11
- const { source, position } = context;
11
+ const { source, position, state } = context;
12
12
  if (position === source.length) return;
13
13
  const char = source[position];
14
14
  consume(1, context);
@@ -38,7 +38,7 @@ export const escsource: EscapableSourceParser = ({ context }) => {
38
38
  default:
39
39
  assert(char !== '\n');
40
40
  if (context.sequential) return new List([new Node(char)]);
41
- let i = next(source, position, delimiter);
41
+ let i = next(source, position, state, delimiter);
42
42
  assert(i > position);
43
43
  i -= position;
44
44
  consume(i - 1, context);
@@ -1,5 +1,5 @@
1
1
  import { TextParser, TxtParser } from '../source';
2
- import { Command } from '../context';
2
+ import { State, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
4
  import { union, consume } from '../../combinator';
5
5
  import { html } from 'typed-dom/dom';
@@ -9,7 +9,7 @@ export const nonWhitespace = /[^ \t ]/g;
9
9
 
10
10
  export const text: TextParser = input => {
11
11
  const { context } = input;
12
- const { source, position } = context;
12
+ const { source, position, state } = context;
13
13
  if (position === source.length) return;
14
14
  const char = source[position];
15
15
  consume(1, context);
@@ -43,7 +43,7 @@ export const text: TextParser = input => {
43
43
  ? nonWhitespace.test(source)
44
44
  ? nonWhitespace.lastIndex - 1
45
45
  : source.length
46
- : next(source, position);
46
+ : next(source, position, state);
47
47
  assert(i > position);
48
48
  const lineend = 0
49
49
  || s && i === source.length
@@ -83,35 +83,28 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
83
83
  }
84
84
  }
85
85
 
86
- export function next(source: string, position: number, delimiter?: RegExp): number {
86
+ export function next(source: string, position: number, state: number, delimiter?: RegExp): number {
87
87
  let index: number;
88
88
  if (delimiter) {
89
89
  delimiter.lastIndex = position + 1;
90
90
  delimiter.test(source);
91
- index = delimiter.lastIndex;
91
+ index = delimiter.lastIndex || position;
92
92
  }
93
93
  else {
94
- index = seek(source, position);
94
+ index = seek(source, position, state);
95
95
  }
96
- if (index === 0) return source.length;
96
+ if (index === position || index === source.length) return source.length;
97
97
  assert(index > position);
98
98
  const char = source[index];
99
99
  switch (char) {
100
- case '$':
101
- case '*':
102
- case '+':
103
- case '~':
104
- case '=':
105
- case '/':
106
- index = backToWhitespace(source, position, index);
107
- break;
108
100
  case '%':
109
- index += index - 1 > position && source.startsWith(' %]', index - 1)
101
+ assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true) || delimiter);
102
+ index += !delimiter && index - 1 > position
110
103
  ? -1
111
104
  : 0;
112
105
  break;
113
106
  case '[':
114
- index += index - 1 > position && source.startsWith(' [|', index - 1)
107
+ index += !delimiter && index - 1 > position && source.startsWith(' [|', index - 1)
115
108
  ? -1
116
109
  : 0;
117
110
  break;
@@ -121,19 +114,15 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
121
114
  : index;
122
115
  break;
123
116
  case '@':
124
- index = backToEmailHead(source, position, index);
117
+ index = ~state & State.autolink
118
+ ? backToEmailHead(source, position, index)
119
+ : index;
125
120
  break;
126
121
  }
127
122
  assert(index > position);
128
123
  return index;
129
124
  }
130
- export function backToWhitespace(source: string, position: number, index: number): number {
131
- const prev = index - 1;
132
- return prev > position && /\s/.test(source[prev])
133
- ? prev
134
- : index;
135
- }
136
- export function backToUrlHead(source: string, position: number, index: number): number {
125
+ function backToUrlHead(source: string, position: number, index: number): number {
137
126
  const delim = index;
138
127
  let state = false;
139
128
  for (let i = index - 1; i >= position; --i) {
@@ -156,7 +145,7 @@ export function backToUrlHead(source: string, position: number, index: number):
156
145
  ? delim
157
146
  : index;
158
147
  }
159
- export function backToEmailHead(source: string, position: number, index: number): number {
148
+ function backToEmailHead(source: string, position: number, index: number): number {
160
149
  const delim = index;
161
150
  let state = false;
162
151
  for (let i = index - 1; i >= position; --i) {
@@ -223,15 +212,13 @@ export function isAlphanumeric(char: string): boolean {
223
212
  // }
224
213
  //};
225
214
 
226
- function seek(source: string, position: number): number {
215
+ function seek(source: string, position: number, state: number): number {
227
216
  for (let i = position + 1; i < source.length; ++i) {
228
217
  const fst = source[i];
229
218
  //if (fst.charCodeAt(0) in dict) return i;
230
219
  switch (fst) {
231
220
  case '\\':
232
221
  case '!':
233
- case '@':
234
- case '#':
235
222
  case '$':
236
223
  case '"':
237
224
  case '`':
@@ -254,6 +241,10 @@ function seek(source: string, position: number): number {
254
241
  case '\r':
255
242
  case '\n':
256
243
  return i;
244
+ case '@':
245
+ case '#':
246
+ if (~state & State.autolink) return i;
247
+ continue;
257
248
  case '+':
258
249
  case '~':
259
250
  case '=':
@@ -263,7 +254,7 @@ function seek(source: string, position: number): number {
263
254
  if (source[i + 1] === fst && source[i + 2] === fst) return i;
264
255
  continue;
265
256
  case '%':
266
- if (source[i + 1] === ']') return i;
257
+ if (source[i + 1] === ']' && isWhitespace(source[i - 1], true)) return i;
267
258
  continue;
268
259
  case ':':
269
260
  if (source[i + 1] === '/' && source[i + 2] === '/') return i;
@@ -8,7 +8,7 @@ import { html } from 'typed-dom/dom';
8
8
  export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
9
9
 
10
10
  export const unescsource: UnescapableSourceParser = ({ context }) => {
11
- const { source, position } = context;
11
+ const { source, position, state } = context;
12
12
  if (position === source.length) return;
13
13
  const char = source[position];
14
14
  consume(1, context);
@@ -31,7 +31,7 @@ export const unescsource: UnescapableSourceParser = ({ context }) => {
31
31
  ? nonWhitespace.test(source)
32
32
  ? nonWhitespace.lastIndex - 1
33
33
  : source.length
34
- : next(source, position, delimiter);
34
+ : next(source, position, state, delimiter);
35
35
  assert(i > position);
36
36
  i -= position;
37
37
  consume(i - 1, context);