securemark 0.294.7 → 0.294.8

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +176 -194
  3. package/markdown.d.ts +13 -36
  4. package/package.json +1 -1
  5. package/src/combinator/control/constraint/block.ts +2 -2
  6. package/src/combinator/control/constraint/line.ts +7 -5
  7. package/src/combinator/control/manipulation/convert.ts +2 -1
  8. package/src/combinator/control/manipulation/fence.ts +4 -4
  9. package/src/combinator/control/manipulation/surround.ts +9 -9
  10. package/src/combinator/data/parser/some.ts +1 -1
  11. package/src/combinator/data/parser/union.ts +6 -2
  12. package/src/parser/api/bind.test.ts +0 -1
  13. package/src/parser/api/normalize.test.ts +5 -8
  14. package/src/parser/api/normalize.ts +4 -2
  15. package/src/parser/autolink.ts +1 -2
  16. package/src/parser/block/extension/fig.ts +4 -1
  17. package/src/parser/block/heading.ts +12 -2
  18. package/src/parser/block/reply/quote.ts +1 -2
  19. package/src/parser/block/ulist.ts +1 -1
  20. package/src/parser/block.ts +0 -4
  21. package/src/parser/header.ts +28 -40
  22. package/src/parser/inline/annotation.ts +2 -3
  23. package/src/parser/inline/autolink/account.ts +48 -17
  24. package/src/parser/inline/autolink/anchor.test.ts +0 -1
  25. package/src/parser/inline/autolink/anchor.ts +16 -15
  26. package/src/parser/inline/autolink/email.test.ts +1 -1
  27. package/src/parser/inline/autolink/email.ts +10 -11
  28. package/src/parser/inline/autolink/hashnum.ts +17 -13
  29. package/src/parser/inline/autolink/hashtag.ts +19 -15
  30. package/src/parser/inline/autolink/url.ts +24 -19
  31. package/src/parser/inline/autolink.ts +1 -2
  32. package/src/parser/inline/bracket.ts +14 -14
  33. package/src/parser/inline/deletion.ts +2 -1
  34. package/src/parser/inline/emphasis.ts +2 -1
  35. package/src/parser/inline/emstrong.ts +2 -1
  36. package/src/parser/inline/extension/index.ts +4 -4
  37. package/src/parser/inline/extension/indexer.ts +1 -1
  38. package/src/parser/inline/extension/label.ts +1 -1
  39. package/src/parser/inline/extension/placeholder.ts +4 -3
  40. package/src/parser/inline/html.ts +4 -4
  41. package/src/parser/inline/htmlentity.ts +2 -2
  42. package/src/parser/inline/insertion.ts +2 -1
  43. package/src/parser/inline/italic.ts +2 -1
  44. package/src/parser/inline/link.ts +7 -20
  45. package/src/parser/inline/mark.ts +2 -1
  46. package/src/parser/inline/math.ts +4 -2
  47. package/src/parser/inline/media.ts +24 -25
  48. package/src/parser/inline/reference.ts +4 -4
  49. package/src/parser/inline/remark.ts +2 -1
  50. package/src/parser/inline/ruby.ts +3 -4
  51. package/src/parser/inline/strong.ts +2 -1
  52. package/src/parser/inline/template.ts +10 -10
  53. package/src/parser/segment.ts +2 -2
  54. package/src/parser/source/escapable.ts +3 -4
  55. package/src/parser/source/line.ts +3 -1
  56. package/src/parser/source/text.ts +5 -10
  57. package/src/parser/source/unescapable.ts +2 -4
  58. package/src/parser/source.ts +1 -2
  59. package/src/parser/inline/autolink/channel.ts +0 -44
@@ -32,7 +32,6 @@ describe('Unit: parser/inline/autolink/anchor', () => {
32
32
  assert.deepStrictEqual(inspect(parser('>>0-A'), ctx), [['<a class="anchor" href="?at=0-A">&gt;&gt;0-A</a>'], '']);
33
33
  assert.deepStrictEqual(inspect(parser('>>0--a'), ctx), [['<a class="anchor" href="?at=0">&gt;&gt;0</a>'], '--a']);
34
34
  assert.deepStrictEqual(inspect(parser('>>2000-0131-2359-59999'), ctx), [['<a class="anchor" href="?at=2000-0131-2359-59999">&gt;&gt;2000-0131-2359-59999</a>'], '']);
35
- assert.deepStrictEqual(inspect(parser('>>A/2000-0131-2359-59'), ctx), [['<a class="anchor" href="/@A/timeline?at=2000-0131-2359-59">&gt;&gt;A/2000-0131-2359-59</a>'], '']);
36
35
  });
37
36
 
38
37
  });
@@ -1,8 +1,9 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { State, Backtrack } from '../../context';
3
3
  import { List, Data } from '../../../combinator/data/parser';
4
- import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
5
- import { unsafelink } from '../link';
4
+ import { state, constraint, surround, lazy } from '../../../combinator';
5
+ import { parse } from '../link';
6
+ import { str } from '../../source';
6
7
  import { define } from 'typed-dom/dom';
7
8
 
8
9
  // Timeline(pseudonym): user/tid
@@ -15,18 +16,18 @@ import { define } from 'typed-dom/dom';
15
16
  // 内部表現はUnixTimeに統一する(時系列順)
16
17
  // 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
17
18
 
18
- export const anchor: AutolinkParser.AnchorParser = lazy(() => rewrite(
19
- open(
19
+ export const anchor: AutolinkParser.AnchorParser = lazy(() => constraint(State.autolink, state(State.autolink,
20
+ surround(
20
21
  /(?<![0-9a-z])>>/yi,
21
- /(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?!-?[0-9a-z@#]|>>|:\S)/yi,
22
+ str(/[0-9a-z]+(?:-[0-9a-z]+)*(?!-?[0-9a-z@#]|>>|:\S)/yi),
23
+ '',
22
24
  false,
23
- [3 | Backtrack.autolink]),
24
- constraint(State.autolink, state(State.autolink, fmap(convert(
25
- source =>
26
- `[${source}]{ ${source.includes('/')
27
- ? `/@${source.slice(2).replace('/', '/timeline?at=')}`
28
- : `?at=${source.slice(2)}`
29
- } }`,
30
- union([unsafelink]),
31
- false),
32
- ([{ value }]) => new List([new Data(define(value, { class: 'anchor' }))]))))));
25
+ [3 | Backtrack.autolink],
26
+ ([, [{ value }]], context) =>
27
+ new List([
28
+ new Data(define(parse(
29
+ new List([new Data(`>>${value}`)]),
30
+ new List([new Data(`?at=${value}`)]),
31
+ context),
32
+ { class: 'anchor' }))
33
+ ])))));
@@ -27,8 +27,8 @@ describe('Unit: parser/inline/autolink/email', () => {
27
27
  assert.deepStrictEqual(inspect(parser('a..b@c'), ctx), undefined);
28
28
  assert.deepStrictEqual(inspect(parser('a++b@c'), ctx), undefined);
29
29
  assert.deepStrictEqual(inspect(parser('a@b.c:d'), ctx), undefined);
30
+ assert.deepStrictEqual(inspect(parser('a@b.domain.com:c'), ctx), undefined);
30
31
  assert.deepStrictEqual(inspect(parser('a@http://host'), ctx), undefined);
31
- assert.deepStrictEqual(inspect(parser(`a@${'b'.repeat(64)}`), ctx), undefined);
32
32
  assert.deepStrictEqual(inspect(parser(' a@b'), ctx), undefined);
33
33
  });
34
34
 
@@ -1,21 +1,20 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { State, Backtrack } from '../../context';
3
3
  import { List, Data } from '../../../combinator/data/parser';
4
- import { union, state, constraint, verify, rewrite, open } from '../../../combinator';
4
+ import { state, constraint, verify, surround } from '../../../combinator';
5
5
  import { str } from '../../source';
6
6
  import { html } from 'typed-dom/dom';
7
7
 
8
8
  // https://html.spec.whatwg.org/multipage/input.html
9
9
 
10
- export const email: AutolinkParser.EmailParser = rewrite(
11
- open(/(?<![0-9a-z][_.+-]?|[@#])(?=[0-9a-z])/yi,
10
+ export const email: AutolinkParser.EmailParser = constraint(State.autolink, state(State.autolink,
11
+ surround(
12
+ /(?<![0-9a-z][_.+-]?|[@#])(?=[0-9a-z])/yi,
12
13
  verify(
13
- str(/[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![.-]?[0-9a-z@#]|>>|:\S)/yi),
14
- ([{ value }]) => value.length <= 255),
14
+ str(/[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,63}@[0-9a-z](?:[.-](?=[0-9a-z])|[0-9a-z]){0,254}(?![.-]?[0-9a-z@#]|>>|:\S)/yi),
15
+ ([{ value }]) => value.length <= 254),
16
+ '',
15
17
  false,
16
- [3 | Backtrack.autolink]),
17
- constraint(State.autolink, state(State.autolink,
18
- union([
19
- ({ context: { source } }) =>
20
- new List([new Data(html('a', { class: 'email', href: `mailto:${source}` }, source))])
21
- ]))));
18
+ [3 | Backtrack.autolink],
19
+ ([, [{ value }]]) =>
20
+ new List([new Data(html('a', { class: 'email', href: `mailto:${value}` }, value))]))));
@@ -1,24 +1,28 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { State, Backtrack } from '../../context';
3
3
  import { List, Data } from '../../../combinator/data/parser';
4
- import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
5
- import { unsafelink } from '../link';
4
+ import { state, constraint, surround, lazy } from '../../../combinator';
5
+ import { parse } from '../link';
6
6
  import { emoji } from './hashtag';
7
+ import { str } from '../../source';
7
8
  import { define } from 'typed-dom/dom';
8
9
 
9
- export const hashnum: AutolinkParser.HashnumParser = lazy(() => rewrite(
10
- open(
10
+ export const hashnum: AutolinkParser.HashnumParser = lazy(() => constraint(State.autolink, state(State.autolink,
11
+ surround(
11
12
  new RegExp([
12
13
  /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
13
14
  ].join('|').replace(/emoji/g, emoji.source), 'yu'),
14
- new RegExp([
15
+ str(new RegExp([
15
16
  /[0-9]{1,9}(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
16
- ].join('|').replace(/emoji/g, emoji.source), 'yu'),
17
+ ].join('|').replace(/emoji/g, emoji.source), 'yu')),
18
+ '',
17
19
  false,
18
- [1 | Backtrack.autolink]),
19
- constraint(State.autolink, state(State.autolink, fmap(convert(
20
- source => `[${source}]{ ${source.slice(1)} }`,
21
- union([unsafelink]),
22
- false),
23
- ([{ value }]) => new List([new Data(define(value, { class: 'hashnum', href: null }))])))),
24
- ));
20
+ [1 | Backtrack.autolink],
21
+ ([, [{ value }]], context) =>
22
+ new List([
23
+ new Data(define(parse(
24
+ new List([new Data(`#${value}`)]),
25
+ new List([new Data(value)]),
26
+ context),
27
+ { class: 'hashnum', href: null }))
28
+ ])))));
@@ -1,8 +1,8 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { State, Backtrack } from '../../context';
3
3
  import { List, Data } from '../../../combinator/data/parser';
4
- import { union, state, constraint, verify, rewrite, surround, convert, fmap, lazy } from '../../../combinator';
5
- import { unsafelink } from '../link';
4
+ import { state, constraint, verify, surround, lazy } from '../../../combinator';
5
+ import { parse } from '../link';
6
6
  import { str } from '../../source';
7
7
  import { define } from 'typed-dom/dom';
8
8
 
@@ -11,22 +11,26 @@ import { define } from 'typed-dom/dom';
11
11
  // https://github.com/tc39/proposal-regexp-unicode-property-escapes#matching-emoji
12
12
  export const emoji = /\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F|\u200D/u;
13
13
 
14
- export const hashtag: AutolinkParser.HashtagParser = lazy(() => rewrite(
15
- verify(surround(
14
+ export const hashtag: AutolinkParser.HashtagParser = lazy(() => constraint(State.autolink, state(State.autolink,
15
+ surround(
16
16
  new RegExp([
17
17
  /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
18
18
  ].join('|').replace(/emoji/g, emoji.source), 'yu'),
19
- str(new RegExp([
20
- /(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source,
21
- ].join('|').replace(/emoji/g, emoji.source), 'yu')),
19
+ verify(
20
+ str(new RegExp([
21
+ /(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source,
22
+ ].join('|').replace(/emoji/g, emoji.source), 'yu')),
23
+ ([{ value }]) => /^[0-9]{0,4}[^0-9]/.test(value)),
22
24
  new RegExp([
23
25
  /(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
24
26
  ].join('|').replace(/emoji/g, emoji.source), 'yu'),
25
- false, undefined, undefined,
26
- [3 | Backtrack.autolink]),
27
- ([{ value }]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(value)),
28
- constraint(State.autolink, state(State.autolink, fmap(convert(
29
- source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`,
30
- union([unsafelink]),
31
- false),
32
- ([{ value }]) => new List([new Data(define(value, { class: 'hashtag' }))]))))));
27
+ false,
28
+ [3 | Backtrack.autolink],
29
+ ([, [{ value }]], context) =>
30
+ new List([
31
+ new Data(define(parse(
32
+ new List([new Data(`#${value}`)]),
33
+ new List([new Data(`/hashtags/${value}`)]),
34
+ context),
35
+ { class: 'hashtag' }))
36
+ ])))));
@@ -1,9 +1,9 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { State, Recursion, Backtrack } from '../../context';
3
- import { List } from '../../../combinator/data/parser';
4
- import { union, tails, some, recursion, precedence, state, constraint, verify, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
3
+ import { List, Data } from '../../../combinator/data/parser';
4
+ import { union, tails, some, recursion, precedence, state, constraint, verify, focus, rewrite, surround, open, lazy } from '../../../combinator';
5
5
  import { inline } from '../../inline';
6
- import { unsafelink } from '../link';
6
+ import { parse } from '../link';
7
7
  import { unescsource, str } from '../../source';
8
8
 
9
9
  export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
@@ -16,10 +16,8 @@ export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
16
16
  false,
17
17
  [3 | Backtrack.autolink]),
18
18
  union([
19
- constraint(State.autolink, state(State.autolink, convert(
20
- url => `{ ${url} }`,
21
- unsafelink,
22
- false))),
19
+ constraint(State.autolink, state(State.autolink, ({ context }) =>
20
+ new List([new Data(parse(new List(), new List([new Data(context.source)]), context))]))),
23
21
  open(str(/[^:]+/y), some(inline)),
24
22
  ])));
25
23
 
@@ -28,21 +26,28 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
28
26
  tails([
29
27
  str('!'),
30
28
  union([
31
- constraint(State.autolink, state(State.autolink, convert(
32
- url => `{ ${url} }`,
33
- unsafelink,
34
- false))),
29
+ constraint(State.autolink, state(State.autolink, ({ context }) => {
30
+ const { source, position } = context;
31
+ context.position -= source[0] === '!' ? 1 : 0;
32
+ context.position += source.length;
33
+ return new List([
34
+ new Data(parse(
35
+ new List(),
36
+ new List([new Data(source.slice(position))]),
37
+ context))
38
+ ]);
39
+ })),
35
40
  open(str(/[^:]+/y), some(inline)),
36
41
  ]),
37
42
  ])));
38
43
 
39
44
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => union([
40
- surround(str('('), recursion(Recursion.terminal, some(union([bracket, unescsource]), ')')), str(')'), true,
41
- undefined, () => new List(), [3 | Backtrack.autolink]),
42
- surround(str('['), recursion(Recursion.terminal, some(union([bracket, unescsource]), ']')), str(']'), true,
43
- undefined, () => new List(), [3 | Backtrack.autolink]),
44
- surround(str('{'), recursion(Recursion.terminal, some(union([bracket, unescsource]), '}')), str('}'), true,
45
- undefined, () => new List(), [3 | Backtrack.autolink]),
46
- surround(str('"'), precedence(2, recursion(Recursion.terminal, some(unescsource, '"'))), str('"'), true,
47
- undefined, () => new List(), [3 | Backtrack.autolink]),
45
+ surround(str('('), recursion(Recursion.terminal, some(union([bracket, unescsource]), ')')), str(')'),
46
+ true, [3 | Backtrack.autolink], undefined, () => new List()),
47
+ surround(str('['), recursion(Recursion.terminal, some(union([bracket, unescsource]), ']')), str(']'),
48
+ true, [3 | Backtrack.autolink], undefined, () => new List()),
49
+ surround(str('{'), recursion(Recursion.terminal, some(union([bracket, unescsource]), '}')), str('}'),
50
+ true, [3 | Backtrack.autolink], undefined, () => new List()),
51
+ surround(str('"'), precedence(2, recursion(Recursion.terminal, some(unescsource, '"'))), str('"'),
52
+ true, [3 | Backtrack.autolink], undefined, () => new List()),
48
53
  ]));
@@ -3,7 +3,6 @@ import { State } from '../context';
3
3
  import { state, lazy } from '../../combinator';
4
4
  import { url, lineurl } from './autolink/url';
5
5
  import { email } from './autolink/email';
6
- import { channel } from './autolink/channel';
7
6
  import { account } from './autolink/account';
8
7
  import { hashtag } from './autolink/hashtag';
9
8
  import { hashnum } from './autolink/hashnum';
@@ -18,7 +17,7 @@ export const autolink: AutolinkParser = lazy(() =>
18
17
  const fst = source[position];
19
18
  switch (fst) {
20
19
  case '@':
21
- return channel(input) || account(input);
20
+ return account(input);
22
21
  case '#':
23
22
  return hashtag(input) || hashnum(input);
24
23
  case '>':
@@ -39,34 +39,35 @@ const p1 = lazy(() => surround(
39
39
  precedence(1, recursion(Recursion.bracket, some(inline, ')', [[')', 1]]))),
40
40
  str(')'),
41
41
  true,
42
+ [2 | Backtrack.bracket],
42
43
  ([as, bs = new List(), cs], { source, position, range = 0 }) => {
43
44
  const str = source.slice(position - range + 1, position - 1);
44
45
  return indexA.test(str)
45
46
  ? new List([new Data(as.head!.value), new Data(str), new Data(cs.head!.value)])
46
47
  : new List([new Data(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Data<string>>).import(cs)))))]);
47
48
  },
48
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
49
- [2 | Backtrack.bracket]));
49
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
50
50
 
51
51
  const p2 = lazy(() => surround(
52
52
  str('('),
53
53
  precedence(1, recursion(Recursion.bracket, some(inline, ')', [[')', 1]]))),
54
54
  str(')'),
55
55
  true,
56
+ [2 | Backtrack.bracket],
56
57
  ([as, bs = [], cs], { source, position, range = 0 }) => {
57
58
  const str = source.slice(position - range + 1, position - 1);
58
59
  return indexF.test(str)
59
60
  ? new List([new Data(as.head!.value), new Data(str), new Data(cs.head!.value)])
60
61
  : new List([new Data(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Data<string>>).import(cs)))))]);
61
62
  },
62
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
63
- [2 | Backtrack.bracket]));
63
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
64
64
 
65
65
  const s1 = lazy(() => surround(
66
66
  str('['),
67
67
  precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
68
68
  str(']'),
69
69
  true,
70
+ [2 | Backtrack.bracket],
70
71
  ([as, bs = new List(), cs], context) => {
71
72
  if (context.state! & State.link) {
72
73
  const { source, position, range = 0 } = context;
@@ -89,35 +90,34 @@ const s1 = lazy(() => surround(
89
90
  }
90
91
  return as.import(bs as List<Data<string>>).import(cs);
91
92
  },
92
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
93
- [2 | Backtrack.bracket]));
93
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
94
94
 
95
95
  const s2 = lazy(() => surround(
96
96
  str('['),
97
97
  precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
98
98
  str(']'),
99
99
  true,
100
+ [2 | Backtrack.bracket],
100
101
  undefined,
101
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
102
- [2 | Backtrack.bracket]));
102
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
103
103
 
104
104
  const c1 = lazy(() => surround(
105
105
  str('{'),
106
106
  precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
107
107
  str('}'),
108
108
  true,
109
+ [2 | Backtrack.bracket],
109
110
  undefined,
110
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
111
- [2 | Backtrack.bracket]));
111
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
112
112
 
113
113
  const c2 = lazy(() => surround(
114
114
  str('{'),
115
115
  precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
116
116
  str('}'),
117
117
  true,
118
+ [2 | Backtrack.bracket],
118
119
  undefined,
119
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
120
- [2 | Backtrack.bracket]));
120
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
121
121
 
122
122
  const d1 = lazy(() => surround(
123
123
  str('"'),
@@ -125,6 +125,6 @@ const d1 = lazy(() => surround(
125
125
  precedence(2, recursion(Recursion.bracket, some(inline, /["\n]/y, [['"', 2], ['\n', 3]]))),
126
126
  str('"'),
127
127
  true,
128
+ [2 | Backtrack.bracket],
128
129
  undefined,
129
- ([as, bs = new List()]) => as.import(bs as List<Data<string>>),
130
- [2 | Backtrack.bracket]));
130
+ ([as, bs = new List()]) => as.import(bs as List<Data<string>>)));
@@ -15,7 +15,8 @@ export const deletion: DeletionParser = lazy(() =>
15
15
  some(inline, blankWith('\n', '~~')),
16
16
  open('\n', some(inline, '~'), true),
17
17
  ]))),
18
- '~~', false,
18
+ '~~',
19
+ false, [],
19
20
  ([, bs], { buffer }) => buffer!.import(bs),
20
21
  ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
21
22
  nodes => new List([new Data(html('del', defrag(unwrap(nodes))))]))));
@@ -17,6 +17,7 @@ export const emphasis: EmphasisParser = lazy(() => surround(
17
17
  some(inline, blankWith('*')),
18
18
  open(some(inline, '*'), inline),
19
19
  ]))))),
20
- str('*'), false,
20
+ str('*'),
21
+ false, [],
21
22
  ([, bs]) => new List([new Data(html('em', defrag(unwrap(bs))))]),
22
23
  ([as, bs]) => bs && as.import(bs as List<Data<string>>)));
@@ -32,7 +32,8 @@ export const emstrong: EmStrongParser = lazy(() =>
32
32
  some(inline, blankWith('*')),
33
33
  open(some(inline, '*'), inline),
34
34
  ])))),
35
- str(/\*{1,3}/y), false,
35
+ str(/\*{1,3}/y),
36
+ false, [],
36
37
  ([, bs, cs], context): Result<Node<EmStrongParser>, Context<EmStrongParser>> => {
37
38
  assert(cs.length === 1);
38
39
  const { buffer = new List() } = context;
@@ -22,12 +22,12 @@ export const index: IndexParser = lazy(() => constraint(State.index, fmap(indexe
22
22
  ]), ']', [[']', 1]])))),
23
23
  str(']'),
24
24
  false,
25
+ [3 | Backtrack.bracket],
25
26
  ([, bs], context) =>
26
27
  context.linebreak === 0 && trimBlankNodeEnd(bs).length > 0
27
28
  ? new List([new Data(html('a', { 'data-index': dataindex(bs) }, defrag(unwrap(bs))))])
28
29
  : undefined,
29
- undefined,
30
- [3 | Backtrack.bracket])),
30
+ undefined)),
31
31
  ns => {
32
32
  if (ns.length === 1) {
33
33
  const el = ns.head!.value as HTMLElement;
@@ -54,14 +54,14 @@ export const signature: IndexParser.SignatureParser = lazy(() => validate('|', s
54
54
  ]), ']'),
55
55
  /(?=])/y,
56
56
  false,
57
+ [3 | Backtrack.bracket],
57
58
  ([, ns], context) => {
58
59
  const index = identity('index', undefined, ns.foldl((acc, { value }) => acc + value, ''))?.slice(7);
59
60
  return index && context.linebreak === 0
60
61
  ? new List([new Data(html('span', { class: 'indexer', 'data-index': index }))])
61
62
  : undefined;
62
63
  },
63
- ([as, bs]) => bs && as.import(bs),
64
- [3 | Backtrack.bracket])));
64
+ ([as, bs]) => bs && as.import(bs))));
65
65
 
66
66
  export function dataindex(nodes: List<Data<string | HTMLElement>>): string | undefined {
67
67
  let node = nodes.last;
@@ -16,4 +16,4 @@ export const indexer: ExtensionParser.IndexerParser = surround(
16
16
  signature,
17
17
  focus(/\|(?=\])/y, () => new List([new Data(html('span', { class: 'indexer', 'data-index': '' }))])),
18
18
  ]),
19
- /\]\s*$/y);
19
+ /\][^\S\n]*(?:$|\n)/y);
@@ -14,7 +14,7 @@ export const segment: ExtensionParser.LabelParser.SegmentParser = clear(union([
14
14
 
15
15
  export const label: ExtensionParser.LabelParser = constraint(State.label, fmap(
16
16
  union([
17
- surround('[', body, ']', false, undefined, undefined, [1 | Backtrack.bracket, 1]),
17
+ surround('[', body, ']', false, [1 | Backtrack.bracket, 1]),
18
18
  body,
19
19
  ]),
20
20
  ([{ value }]) => new List([
@@ -17,7 +17,9 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surroun
17
17
  str(/\[[:^|]/y),
18
18
  precedence(1, recursion(Recursion.inline,
19
19
  tightStart(some(union([inline]), ']', [[']', 1]])))),
20
- str(']'), false,
20
+ str(']'),
21
+ false,
22
+ [3 | Backtrack.bracket],
21
23
  (_, context) => new List([
22
24
  new Data(html('span',
23
25
  {
@@ -26,5 +28,4 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surroun
26
28
  },
27
29
  context.source.slice(context.position - context.range!, context.position)))
28
30
  ]),
29
- ([as, bs]) => bs && as.import(bs as List<Data<string>>),
30
- [3 | Backtrack.bracket]));
31
+ ([as, bs]) => bs && as.import(bs as List<Data<string>>)));
@@ -26,7 +26,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
26
26
  str(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/y),
27
27
  some(union([attribute])),
28
28
  open(str(/ ?/y), str('>'), true),
29
- true,
29
+ true, [],
30
30
  ([as, bs = new List(), cs], context) =>
31
31
  new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
32
32
  ([as, bs = new List()], context) =>
@@ -38,7 +38,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
38
38
  surround<HTMLParser.TagParser, string>(
39
39
  surround(
40
40
  str(`<${tag}`), some(attribute), open(str(/ ?/y), str('>'), true),
41
- true,
41
+ true, [],
42
42
  ([as, bs = new List(), cs]) => as.import(bs).import(cs),
43
43
  ([as, bs = new List()]) => as.import(bs)),
44
44
  // 不可視のHTML構造が可視構造を変化させるべきでない。
@@ -51,7 +51,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
51
51
  open('\n', some(inline, `</${tag}>`), true),
52
52
  ])))),
53
53
  str(`</${tag}>`),
54
- true,
54
+ true, [],
55
55
  ([as, bs = new List(), cs], context) =>
56
56
  new List([new Data(elem(tag, true, [...unwrap(as)], bs, cs, context))]),
57
57
  ([as, bs = new List()], context) =>
@@ -63,7 +63,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
63
63
  str(/<[a-z]+(?=[ >])/yi),
64
64
  some(union([attribute])),
65
65
  open(str(/ ?/y), str('>'), true),
66
- true,
66
+ true, [],
67
67
  ([as, bs = new List(), cs], context) =>
68
68
  new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
69
69
  ([as, bs = new List()], context) =>
@@ -9,11 +9,11 @@ import { html } from 'typed-dom/dom';
9
9
  export const unsafehtmlentity: UnsafeHTMLEntityParser = surround(
10
10
  str('&'), str(/[0-9A-Za-z]+/y), str(';'),
11
11
  false,
12
+ [3 | Backtrack.bracket],
12
13
  ([as, bs, cs]) =>
13
14
  new List([new Data(parser(as.head!.value + bs.head!.value + cs.head!.value))]),
14
15
  ([as, bs]) =>
15
- new List([new Data(as.head!.value + (bs?.head?.value ?? ''))]),
16
- [3 | Backtrack.bracket]);
16
+ new List([new Data(as.head!.value + (bs?.head?.value ?? ''))]));
17
17
 
18
18
  export const htmlentity: HTMLEntityParser = fmap(
19
19
  union([unsafehtmlentity]),
@@ -15,7 +15,8 @@ export const insertion: InsertionParser = lazy(() =>
15
15
  some(inline, blankWith('\n', '++')),
16
16
  open('\n', some(inline, '+'), true),
17
17
  ]))),
18
- '++', false,
18
+ '++',
19
+ false, [],
19
20
  ([, bs], { buffer }) => buffer!.import(bs),
20
21
  ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
21
22
  nodes => new List([new Data(html('ins', defrag(unwrap(nodes))))]))));
@@ -18,7 +18,8 @@ export const italic: ItalicParser = lazy(() =>
18
18
  some(inline, blankWith('///')),
19
19
  open(some(inline, '/'), inline),
20
20
  ])))),
21
- '///', false,
21
+ '///',
22
+ false, [],
22
23
  ([, bs], { buffer }) => buffer!.import(bs),
23
24
  ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
24
25
  nodes => new List([new Data(html('i', defrag(unwrap(nodes))))]))));
@@ -2,10 +2,10 @@ 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, surround, open, setBacktrack, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
+ import { union, inits, sequence, subsequence, some, creation, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
6
6
  import { inline, media, shortmedia } from '../inline';
7
7
  import { attributes } from './html';
8
- import { unescsource, str } from '../source';
8
+ import { str } from '../source';
9
9
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
10
10
  import { unwrap, invalid, stringify } from '../util';
11
11
  import { ReadonlyURL } from 'spica/url';
@@ -24,12 +24,11 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
24
24
  trimBlankStart(some(union([inline]), ']', [[']', 1]])),
25
25
  ']',
26
26
  true,
27
+ [3 | Backtrack.bracket, 3 | Backtrack.link, 2 | Backtrack.ruby],
27
28
  ([, ns = new List()], context) =>
28
29
  context.linebreak === 0
29
30
  ? ns.push(new Data(Command.Separator)) && ns
30
- : undefined,
31
- undefined,
32
- [3 | Backtrack.bracket, 3 | Backtrack.link, 2 | Backtrack.ruby])),
31
+ : undefined)),
33
32
  // `{ `と`{`で個別にバックトラックが発生し+1nされる。
34
33
  // 自己再帰的にパースしてもオプションの不要なパースによる計算量の増加により相殺される。
35
34
  dup(surround(
@@ -37,14 +36,14 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
37
36
  inits([uri, some(option)]),
38
37
  / ?}/y,
39
38
  false,
39
+ [3 | Backtrack.link],
40
40
  undefined,
41
41
  ([as, bs], context) => {
42
42
  if (!bs) return;
43
43
  const head = context.position - context.range!;
44
44
  setBacktrack(context, [2 | Backtrack.link], head);
45
45
  return as.import(bs).push(new Data(Command.Cancel)) && as;
46
- },
47
- [3 | Backtrack.link])),
46
+ })),
48
47
  ]),
49
48
  ([{ value: content }, { value: params = undefined } = {}], context) => {
50
49
  if (content.last!.value === Command.Separator) {
@@ -87,18 +86,6 @@ export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State
87
86
  ([{ value: content }, { value: params }], context) =>
88
87
  new List([new Data(parse(content, params as List<Data<string>>, context))]))))));
89
88
 
90
- export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
91
- creation(10,
92
- bind(reverse(tails([
93
- dup(surround(
94
- '[',
95
- some(union([unescsource]), ']'),
96
- ']')),
97
- dup(surround(/{(?![{}])/y, inits([uri, some(option)]), / ?}/y)),
98
- ])),
99
- ([{ value: params }, { value: content } = new Data(new List<Data<string>>())], context) =>
100
- new List([new Data(parse(content, params, context))]))));
101
-
102
89
  export const uri: LinkParser.ParameterParser.UriParser = union([
103
90
  open(/ /y, str(/\S+/y)),
104
91
  str(/[^\s{}]+/y),
@@ -110,7 +97,7 @@ export const option: LinkParser.ParameterParser.OptionParser = union([
110
97
  str(/ [^\s{}]+/y),
111
98
  ]);
112
99
 
113
- function parse(
100
+ export function parse(
114
101
  content: List<Data<string | HTMLElement>>,
115
102
  params: List<Data<string>>,
116
103
  context: MarkdownParser.Context,
@@ -16,7 +16,8 @@ export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mar
16
16
  some(inline, blankWith('==')),
17
17
  open(some(inline, '='), inline),
18
18
  ])))),
19
- '==', false,
19
+ '==',
20
+ false, [],
20
21
  ([, bs], { buffer }) => buffer!.import(bs),
21
22
  ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
22
23
  (nodes, { id }) => {