securemark 0.294.6 → 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 (62) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +226 -216
  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/indent.ts +3 -5
  10. package/src/combinator/control/manipulation/surround.ts +47 -18
  11. package/src/combinator/data/parser/some.ts +1 -1
  12. package/src/combinator/data/parser/union.ts +6 -2
  13. package/src/parser/api/bind.test.ts +0 -1
  14. package/src/parser/api/normalize.test.ts +5 -8
  15. package/src/parser/api/normalize.ts +11 -11
  16. package/src/parser/api/parse.test.ts +3 -3
  17. package/src/parser/autolink.ts +1 -2
  18. package/src/parser/block/extension/fig.ts +4 -1
  19. package/src/parser/block/heading.ts +12 -2
  20. package/src/parser/block/reply/quote.ts +1 -2
  21. package/src/parser/block/ulist.ts +1 -1
  22. package/src/parser/block.ts +0 -4
  23. package/src/parser/header.ts +28 -40
  24. package/src/parser/inline/annotation.ts +2 -3
  25. package/src/parser/inline/autolink/account.ts +47 -17
  26. package/src/parser/inline/autolink/anchor.test.ts +0 -1
  27. package/src/parser/inline/autolink/anchor.ts +15 -15
  28. package/src/parser/inline/autolink/email.test.ts +1 -1
  29. package/src/parser/inline/autolink/email.ts +10 -11
  30. package/src/parser/inline/autolink/hashnum.ts +17 -14
  31. package/src/parser/inline/autolink/hashtag.ts +23 -19
  32. package/src/parser/inline/autolink/url.ts +24 -19
  33. package/src/parser/inline/autolink.ts +36 -25
  34. package/src/parser/inline/bracket.ts +14 -14
  35. package/src/parser/inline/deletion.ts +2 -1
  36. package/src/parser/inline/emphasis.ts +2 -1
  37. package/src/parser/inline/emstrong.ts +2 -1
  38. package/src/parser/inline/extension/index.ts +4 -4
  39. package/src/parser/inline/extension/indexer.ts +1 -1
  40. package/src/parser/inline/extension/label.ts +1 -1
  41. package/src/parser/inline/extension/placeholder.ts +4 -3
  42. package/src/parser/inline/html.ts +5 -5
  43. package/src/parser/inline/htmlentity.ts +3 -3
  44. package/src/parser/inline/insertion.ts +2 -1
  45. package/src/parser/inline/italic.ts +2 -1
  46. package/src/parser/inline/link.ts +7 -20
  47. package/src/parser/inline/mark.ts +2 -1
  48. package/src/parser/inline/math.ts +4 -2
  49. package/src/parser/inline/media.ts +24 -25
  50. package/src/parser/inline/reference.ts +4 -4
  51. package/src/parser/inline/remark.ts +2 -1
  52. package/src/parser/inline/ruby.ts +3 -4
  53. package/src/parser/inline/strong.ts +2 -1
  54. package/src/parser/inline/template.ts +10 -10
  55. package/src/parser/inline.ts +2 -1
  56. package/src/parser/segment.ts +2 -2
  57. package/src/parser/source/escapable.ts +3 -4
  58. package/src/parser/source/line.ts +3 -1
  59. package/src/parser/source/text.ts +8 -13
  60. package/src/parser/source/unescapable.ts +2 -4
  61. package/src/parser/source.ts +1 -2
  62. package/src/parser/inline/autolink/channel.ts +0 -44
@@ -1,7 +1,6 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
2
  import { List, Data } from '../combinator/data/parser';
3
- import { union, inits, some, block, line, validate, focus, rewrite, clear, convert, lazy, fmap } from '../combinator';
4
- import { segment } from './segment';
3
+ import { union, inits, some, block, line, validate, focus, clear, convert, lazy, fmap } from '../combinator';
5
4
  import { str } from './source';
6
5
  import { unwrap, invalid } from './util';
7
6
  import { normalize } from './api/normalize';
@@ -10,44 +9,33 @@ import { html, defrag } from 'typed-dom/dom';
10
9
  export const header: MarkdownParser.HeaderParser = lazy(() => validate(
11
10
  /---+ *\r?\n(?=\S)/y,
12
11
  inits([
13
- rewrite(
14
- ({ context }) => {
15
- const { source } = context;
16
- if (context.header ?? true) {
17
- context.position += segment(source).next().value!.length;
18
- }
19
- else {
20
- context.position = source.length;
21
- }
22
- return new List();
23
- },
24
- block(
25
- union([
26
- validate(({ context }) => context.header ?? true,
27
- focus(/(---+) *\r?\n(?:[A-Za-z][0-9A-Za-z]*(?:-[0-9A-Za-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,100}\1 *(?:$|\r?\n)/y,
28
- convert(source =>
29
- normalize(source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n'))).replace(/(\S)\s+$/mg, '$1'),
30
- fmap(
31
- some(union([field])),
32
- ns => new List([
33
- new Data(html('aside', { class: 'header' }, [
34
- html('details',
35
- { open: '' },
36
- defrag(unwrap(ns.unshift(new Data(html('summary', 'Header'))) && ns))),
37
- ])),
38
- ])), false))),
39
- ({ context }) => {
40
- const { source, position } = context;
41
- context.position += source.length;
42
- return new List([
43
- new Data(html('pre', {
44
- class: 'invalid',
45
- translate: 'no',
46
- ...invalid('header', 'syntax', 'Invalid syntax'),
47
- }, normalize(source.slice(position)))),
48
- ]);
49
- },
50
- ]))),
12
+ block(
13
+ union([
14
+ validate(({ context }) => context.header ?? true,
15
+ focus(/(---+) *\r?\n(?:[A-Za-z][0-9A-Za-z]*(?:-[0-9A-Za-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,100}\1 *(?:$|\r?\n)/y,
16
+ convert(source =>
17
+ normalize(source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n'))).replace(/(\S)\s+$/mg, '$1'),
18
+ fmap(
19
+ some(union([field])),
20
+ ns => new List([
21
+ new Data(html('aside', { class: 'header' }, [
22
+ html('details',
23
+ { open: '' },
24
+ defrag(unwrap(ns.unshift(new Data(html('summary', 'Header'))) && ns))),
25
+ ])),
26
+ ])), false))),
27
+ ({ context }) => {
28
+ const { source, position } = context;
29
+ context.position += source.length;
30
+ return new List([
31
+ new Data(html('pre', {
32
+ class: 'invalid',
33
+ translate: 'no',
34
+ ...invalid('header', 'syntax', 'Invalid syntax'),
35
+ }, normalize(source.slice(position)))),
36
+ ]);
37
+ },
38
+ ])),
51
39
  clear(str(/ *\r?\n/y)),
52
40
  ])));
53
41
 
@@ -13,9 +13,8 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
13
13
  trimBlankStart(some(union([inline]), ')', [[')', 1]])))),
14
14
  '))',
15
15
  false,
16
+ [1 | Backtrack.bracket, 3 | Backtrack.doublebracket],
16
17
  ([, ns], context) =>
17
18
  context.linebreak === 0
18
19
  ? new List([new Data(html('sup', { class: 'annotation' }, [html('span', defrag(unwrap(trimBlankNodeEnd(ns))))]))])
19
- : undefined,
20
- undefined,
21
- [1 | Backtrack.bracket, 3 | Backtrack.doublebracket])));
20
+ : undefined)));
@@ -1,26 +1,56 @@
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, surround, convert, fmap, lazy } from '../../../combinator';
5
- import { unsafelink } from '../link';
4
+ import { some, state, constraint, verify, surround, lazy } from '../../../combinator';
5
+ import { parse } from '../link';
6
+ import { emoji } from './hashtag';
6
7
  import { str } from '../../source';
7
8
  import { define } from 'typed-dom/dom';
8
9
 
9
10
  // https://example/@user must be a user page or a redirect page going there.
11
+ // https://example/@user?ch=a+b must be a user channel page or a redirect page going there.
10
12
 
11
- export const account: AutolinkParser.AccountParser = lazy(() => rewrite(
13
+ export const account: AutolinkParser.AccountParser = lazy(() => constraint(State.autolink, state(State.autolink,
12
14
  surround(
13
- /(?<![0-9a-z])@/yi,
14
- str(/[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])?)*\//yi),
15
- str(/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@#]|>>|:\S)/yi),
16
- true, undefined, undefined,
17
- [3 | Backtrack.autolink]),
18
- constraint(State.autolink, state(State.autolink, fmap(convert(
19
- source =>
20
- `[${source}]{ ${source.includes('/')
21
- ? `https://${source.slice(1).replace('/', '/@')}`
22
- : `/${source}`
23
- } }`,
24
- union([unsafelink]),
25
- false),
26
- ([{ value }]) => new List([new Data(define(value, { class: 'account' }))]))))));
15
+ surround(
16
+ /(?<![0-9a-z])@/yi,
17
+ str(/[0-9a-z](?:[.-](?=[0-9a-z])|[0-9a-z]){0,254}\/|/yi),
18
+ str(/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![-.]?[0-9a-z@]|>>|:\S)/yi)),
19
+ some(surround(
20
+ '#',
21
+ verify(
22
+ str(new RegExp([
23
+ /(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^\p{C}\p{S}\p{P}\s]|emoji))+/yu.source,
24
+ ].join('|').replace(/emoji/g, emoji.source), 'yu')),
25
+ ([{ value }]) => /^[0-9]{0,4}[^0-9]/.test(value)),
26
+ new RegExp([
27
+ /(?![0-9a-z@]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
28
+ ].join('|').replace(/emoji/g, emoji.source), 'yu'),
29
+ false,
30
+ [3 | Backtrack.autolink])),
31
+ '',
32
+ false,
33
+ [3 | Backtrack.autolink],
34
+ ([[{ value: host }, { value: account }], nodes], context) => {
35
+ const hashes = nodes.foldl((acc, { value }) => acc + '#' + value, '');
36
+ const param = nodes.foldl((acc, { value }) => acc ? acc + '+' + value : value, '');
37
+ return new List([
38
+ new Data(define(
39
+ parse(
40
+ new List([new Data(`@${host}${account}${hashes}`)]),
41
+ new List([new Data(host ? `https://${host}@${account}?ch=${param}` : `/@${account}?ch=${param}`)]),
42
+ context),
43
+ { class: 'channel' }))
44
+ ]);
45
+ },
46
+ ([[{ value: host }, { value: account }]], context) => {
47
+ if (context.source[context.position] === '#') return;
48
+ return new List([
49
+ new Data(define(
50
+ parse(
51
+ new List([new Data(`@${host}${account}`)]),
52
+ new List([new Data(host ? `https://${host}@${account}` : `/@${account}`)]),
53
+ context),
54
+ { class: 'account' }))
55
+ ]);
56
+ }))));
@@ -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,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, 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 { str } from '../../source';
7
7
  import { define } from 'typed-dom/dom';
8
8
 
@@ -16,18 +16,18 @@ import { define } from 'typed-dom/dom';
16
16
  // 内部表現はUnixTimeに統一する(時系列順)
17
17
  // 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
18
18
 
19
- export const anchor: AutolinkParser.AnchorParser = lazy(() => rewrite(
20
- open(
19
+ export const anchor: AutolinkParser.AnchorParser = lazy(() => constraint(State.autolink, state(State.autolink,
20
+ surround(
21
21
  /(?<![0-9a-z])>>/yi,
22
- str(/(?:[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
+ '',
23
24
  false,
24
- [3 | Backtrack.autolink]),
25
- constraint(State.autolink, state(State.autolink, fmap(convert(
26
- source =>
27
- `[${source}]{ ${source.includes('/')
28
- ? `/@${source.slice(2).replace('/', '/timeline?at=')}`
29
- : `?at=${source.slice(2)}`
30
- } }`,
31
- union([unsafelink]),
32
- false),
33
- ([{ 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,25 +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
7
  import { str } from '../../source';
8
8
  import { define } from 'typed-dom/dom';
9
9
 
10
- export const hashnum: AutolinkParser.HashnumParser = lazy(() => rewrite(
11
- open(
10
+ export const hashnum: AutolinkParser.HashnumParser = lazy(() => constraint(State.autolink, state(State.autolink,
11
+ surround(
12
12
  new RegExp([
13
- /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yiu.source,
14
- ].join('').replace(/emoji/g, emoji.source), 'yu'),
13
+ /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
14
+ ].join('|').replace(/emoji/g, emoji.source), 'yu'),
15
15
  str(new RegExp([
16
16
  /[0-9]{1,9}(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
17
- ].join('').replace(/emoji/g, emoji.source), 'yu')),
17
+ ].join('|').replace(/emoji/g, emoji.source), 'yu')),
18
+ '',
18
19
  false,
19
- [1 | Backtrack.autolink]),
20
- constraint(State.autolink, state(State.autolink, fmap(convert(
21
- source => `[${source}]{ ${source.slice(1)} }`,
22
- union([unsafelink]),
23
- false),
24
- ([{ value }]) => new List([new Data(define(value, { class: 'hashnum', href: null }))])))),
25
- ));
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
+ new RegExp([
17
+ /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yu.source,
18
+ ].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)),
16
24
  new RegExp([
17
- /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yiu.source,
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')),
22
- str(new RegExp([
23
25
  /(?![0-9a-z@#]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
24
- ].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' }))]))))));
26
+ ].join('|').replace(/emoji/g, emoji.source), 'yu'),
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
  ]));
@@ -1,35 +1,46 @@
1
1
  import { AutolinkParser } from '../inline';
2
2
  import { State } from '../context';
3
- import { union, state, validate, lazy } from '../../combinator';
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
- import { hashtag, emoji } from './autolink/hashtag';
7
+ import { hashtag } from './autolink/hashtag';
9
8
  import { hashnum } from './autolink/hashnum';
10
9
  import { anchor } from './autolink/anchor';
10
+ import { isAlphanumeric } from '../source/text';
11
11
 
12
12
  export const autolink: AutolinkParser = lazy(() =>
13
- validate(new RegExp([
14
- /(?<![0-9a-z])@/yi.source,
15
- /(?<![^\p{C}\p{S}\p{P}\s]|emoji)#/yiu.source,
16
- /(?<![0-9a-z])>>/yi.source,
17
- /(?<![0-9a-z][.+-]?|[@#])!?[0-9a-z]/yi.source,
18
- ].join('|').replace(/emoji/g, emoji.source), 'yiu'),
19
13
  state(~State.autolink,
20
- union([
21
- lineurl,
22
- url,
23
- email,
24
- // Escape unmatched email-like strings.
25
- //str(/[0-9a-z]+(?:[_.+-][0-9a-z]+[:@]?|:|@(?=@))*/yi),
26
- channel,
27
- account,
28
- // Escape unmatched account-like strings.
29
- //str(/@+(?:[0-9a-z]+(?:[_.+-][0-9a-z]+)*)?/yi),
30
- hashtag,
31
- hashnum,
32
- // Escape unmatched hashtag-like strings.
33
- //str(new RegExp(/#+(?:(?:[^\p{C}\p{S}\p{P}\s]|emoji)+(?:['_.+-](?:[^\p{C}\p{S}\p{P}\s]|emoji)+)*)?/yu.source.replace(/emoji/g, emoji), 'yu')),
34
- anchor,
35
- ]))));
14
+ input => {
15
+ const { context: { source, position } } = input;
16
+ if (position === source.length) return;
17
+ const fst = source[position];
18
+ switch (fst) {
19
+ case '@':
20
+ return account(input);
21
+ case '#':
22
+ return hashtag(input) || hashnum(input);
23
+ case '>':
24
+ return anchor(input);
25
+ case '!':
26
+ if (!source.startsWith('http', position + 1)) break;
27
+ if (position === 0) return lineurl(input);
28
+ switch (source[position - 1]) {
29
+ case '\r':
30
+ case '\n':
31
+ return lineurl(input);
32
+ }
33
+ break;
34
+ case 'h':
35
+ if (!source.startsWith('http', position)) return;
36
+ if (position === 0) return lineurl(input) || url(input) || email(input);
37
+ switch (source[position - 1]) {
38
+ case '\r':
39
+ case '\n':
40
+ return lineurl(input) || url(input) || email(input);
41
+ }
42
+ return url(input) || email(input);
43
+ default:
44
+ if (isAlphanumeric(fst)) return email(input);
45
+ }
46
+ }));
@@ -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;