securemark 0.276.5 → 0.278.0

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 (42) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +12 -12
  3. package/design.md +4 -0
  4. package/dist/index.js +85 -48
  5. package/markdown.d.ts +25 -8
  6. package/package.json +1 -1
  7. package/src/parser/api/parse.test.ts +2 -2
  8. package/src/parser/block/dlist.test.ts +1 -1
  9. package/src/parser/block/extension/fig.test.ts +1 -1
  10. package/src/parser/block/heading.test.ts +2 -2
  11. package/src/parser/block/paragraph.test.ts +12 -9
  12. package/src/parser/inline/autolink/account.test.ts +3 -1
  13. package/src/parser/inline/autolink/account.ts +2 -2
  14. package/src/parser/inline/autolink/email.test.ts +0 -3
  15. package/src/parser/inline/autolink/email.ts +1 -1
  16. package/src/parser/inline/autolink/hashnum.test.ts +4 -4
  17. package/src/parser/inline/autolink/hashnum.ts +1 -1
  18. package/src/parser/inline/autolink/hashtag.test.ts +8 -7
  19. package/src/parser/inline/autolink/hashtag.ts +2 -2
  20. package/src/parser/inline/autolink.ts +6 -13
  21. package/src/parser/inline/deletion.test.ts +2 -2
  22. package/src/parser/inline/emphasis.test.ts +35 -26
  23. package/src/parser/inline/emphasis.ts +11 -4
  24. package/src/parser/inline/emstrong.ts +62 -0
  25. package/src/parser/inline/extension/index.test.ts +6 -6
  26. package/src/parser/inline/extension/indexee.ts +5 -5
  27. package/src/parser/inline/extension/placeholder.test.ts +4 -4
  28. package/src/parser/inline/insertion.test.ts +2 -2
  29. package/src/parser/inline/link.test.ts +1 -1
  30. package/src/parser/inline/link.ts +2 -2
  31. package/src/parser/inline/mark.test.ts +1 -1
  32. package/src/parser/inline/{comment.test.ts → remark.test.ts} +26 -26
  33. package/src/parser/inline/{comment.ts → remark.ts} +3 -3
  34. package/src/parser/inline/strong.test.ts +32 -25
  35. package/src/parser/inline/strong.ts +8 -4
  36. package/src/parser/inline.test.ts +102 -22
  37. package/src/parser/inline.ts +6 -3
  38. package/src/parser/processor/figure.ts +3 -2
  39. package/src/parser/processor/note.ts +4 -3
  40. package/src/parser/source/text.test.ts +0 -1
  41. package/src/parser/source/text.ts +0 -1
  42. package/src/renderer/render/media/twitter.ts +1 -1
@@ -33,10 +33,12 @@ describe('Unit: parser/inline/autolink/account', () => {
33
33
  assert.deepStrictEqual(inspect(parser('@a-')), [['<a class="account" href="/@a">@a</a>'], '-']);
34
34
  assert.deepStrictEqual(inspect(parser('@a-b')), [['<a class="account" href="/@a-b">@a-b</a>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser('@a--b')), [['<a class="account" href="/@a">@a</a>'], '--b']);
36
+ assert.deepStrictEqual(inspect(parser('@a.')), [['<a class="account" href="/@a">@a</a>'], '.']);
37
+ assert.deepStrictEqual(inspect(parser('@a.domain.com')), [['<a class="account" href="/@a.domain.com">@a.domain.com</a>'], '']);
36
38
  assert.deepStrictEqual(inspect(parser('@http://host')), [['<a class="account" href="/@http">@http</a>'], '://host']);
37
39
  assert.deepStrictEqual(inspect(parser('@ttp://host')), [['<a class="account" href="/@ttp">@ttp</a>'], '://host']);
38
40
  assert.deepStrictEqual(inspect(parser('@domain/a')), [['<a class="account" href="https://domain/@a" target="_blank">@domain/a</a>'], '']);
39
- assert.deepStrictEqual(inspect(parser('@domain.co.jp/a')), [['<a class="account" href="https://domain.co.jp/@a" target="_blank">@domain.co.jp/a</a>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('@domain.com/a')), [['<a class="account" href="https://domain.com/@a" target="_blank">@domain.com/a</a>'], '']);
40
42
  });
41
43
 
42
44
  });
@@ -12,8 +12,8 @@ export const account: AutolinkParser.AccountParser = lazy(() => fmap(rewrite(
12
12
  open(
13
13
  '@',
14
14
  tails([
15
- str(/^[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*\//i),
16
- str(/^[a-z][0-9a-z]*(?:-[0-9a-z]+)*/i),
15
+ 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])?)*\//i),
16
+ str(/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*/i),
17
17
  ]))),
18
18
  convert(
19
19
  source =>
@@ -8,9 +8,6 @@ describe('Unit: parser/inline/autolink/email', () => {
8
8
 
9
9
  it('invalid', () => {
10
10
  assert.deepStrictEqual(inspect(parser('')), undefined);
11
- assert.deepStrictEqual(inspect(parser('a_b')), [['a'], '_b']);
12
- assert.deepStrictEqual(inspect(parser('a_b_c')), [['a'], '_b_c']);
13
- assert.deepStrictEqual(inspect(parser(`a_${'b'.repeat(255 - 2)}@`)), [[`a_${'b'.repeat(255 - 2)}@`], '']);
14
11
  assert.deepStrictEqual(inspect(parser('a@')), [['a@'], '']);
15
12
  assert.deepStrictEqual(inspect(parser('a@+')), [['a@'], '+']);
16
13
  assert.deepStrictEqual(inspect(parser('a@_')), [['a@'], '_']);
@@ -6,6 +6,6 @@ import { html } from 'typed-dom/dom';
6
6
  // https://html.spec.whatwg.org/multipage/input.html
7
7
 
8
8
  export const email: AutolinkParser.EmailParser = creation(rewrite(verify(
9
- str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=\w)){0,61}[0-9a-z])?)*(?![0-9a-z])/i),
9
+ 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])/i),
10
10
  ([source]) => source.length <= 255),
11
11
  ({ source }) => [[html('a', { class: 'email', href: `mailto:${source}` }, source)], '']));
@@ -10,6 +10,7 @@ describe('Unit: parser/inline/autolink/hashnum', () => {
10
10
  assert.deepStrictEqual(inspect(parser('')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('#')), [['#'], '']);
12
12
  assert.deepStrictEqual(inspect(parser('# ')), [['#'], ' ']);
13
+ assert.deepStrictEqual(inspect(parser('#1_')), [['#1_'], '']);
13
14
  assert.deepStrictEqual(inspect(parser('#1#')), [['#1#'], '']);
14
15
  assert.deepStrictEqual(inspect(parser('#1#2')), [['#1#2'], '']);
15
16
  assert.deepStrictEqual(inspect(parser('#1#2#3')), [['#1#2#3'], '']);
@@ -32,19 +33,18 @@ describe('Unit: parser/inline/autolink/hashnum', () => {
32
33
  assert.deepStrictEqual(inspect(parser('0##a')), [['0##a'], '']);
33
34
  assert.deepStrictEqual(inspect(parser('あ#1')), [['あ#1'], '']);
34
35
  assert.deepStrictEqual(inspect(parser(' #1')), undefined);
35
- assert.deepStrictEqual(inspect(parser('#12345678901234567')), [['#12345678901234567'], '']);
36
- assert.deepStrictEqual(inspect(parser(`#${'1'.repeat(16)}a`)), [[`#${'1'.repeat(16)}a`], '']);
36
+ assert.deepStrictEqual(inspect(parser(`#${'1'.repeat(10)}`)), [[`#${'1'.repeat(10)}`], '']);
37
+ assert.deepStrictEqual(inspect(parser(`#${'1'.repeat(10)}a`)), [[`#${'1'.repeat(10)}a`], '']);
37
38
  });
38
39
 
39
40
  it('valid', () => {
40
41
  assert.deepStrictEqual(inspect(parser('#1')), [['<a class="hashnum">#1</a>'], '']);
41
- assert.deepStrictEqual(inspect(parser('#1_')), [['<a class="hashnum">#1</a>'], '_']);
42
42
  assert.deepStrictEqual(inspect(parser('#1 ')), [['<a class="hashnum">#1</a>'], ' ']);
43
43
  assert.deepStrictEqual(inspect(parser('#1\n')), [['<a class="hashnum">#1</a>'], '\n']);
44
44
  assert.deepStrictEqual(inspect(parser('#1\\')), [['<a class="hashnum">#1</a>'], '\\']);
45
45
  assert.deepStrictEqual(inspect(parser('#1\\ ')), [['<a class="hashnum">#1</a>'], '\\ ']);
46
46
  assert.deepStrictEqual(inspect(parser('#1\\\n')), [['<a class="hashnum">#1</a>'], '\\\n']);
47
- assert.deepStrictEqual(inspect(parser('#1234567890123456')), [['<a class="hashnum">#1234567890123456</a>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('#123456789')), [['<a class="hashnum">#123456789</a>'], '']);
48
48
  });
49
49
 
50
50
  });
@@ -8,7 +8,7 @@ import { define } from 'typed-dom/dom';
8
8
 
9
9
  export const hashnum: AutolinkParser.HashnumParser = lazy(() => fmap(rewrite(
10
10
  constraint(State.shortcut, false,
11
- open('#', str(new RegExp(/^[0-9]{1,16}(?![^\p{C}\p{S}\p{P}\s]|emoji|')/u.source.replace(/emoji/, emoji), 'u')))),
11
+ open('#', str(new RegExp(/^[0-9]{1,9}(?![^\p{C}\p{S}\p{P}\s]|emoji|['_])/u.source.replace(/emoji/, emoji), 'u')))),
12
12
  convert(
13
13
  source => `[${source}]{ ${source.slice(1)} }`,
14
14
  union([unsafelink]))),
@@ -20,8 +20,11 @@ describe('Unit: parser/inline/autolink/hashtag', () => {
20
20
  assert.deepStrictEqual(inspect(parser('##')), [['##'], '']);
21
21
  assert.deepStrictEqual(inspect(parser('##a')), [['##a'], '']);
22
22
  assert.deepStrictEqual(inspect(parser('###a')), [['###a'], '']);
23
- assert.deepStrictEqual(inspect(parser('#_')), [['#'], '_']);
24
- assert.deepStrictEqual(inspect(parser('#_a')), [['#'], '_a']);
23
+ assert.deepStrictEqual(inspect(parser(`#'`)), [[`#'`], '']);
24
+ assert.deepStrictEqual(inspect(parser(`#'0`)), [[`#'0`], '']);
25
+ assert.deepStrictEqual(inspect(parser(`#'00`)), [[`#'00`], '']);
26
+ assert.deepStrictEqual(inspect(parser('#_')), [['#_'], '']);
27
+ assert.deepStrictEqual(inspect(parser('#_a')), [['#_a'], '']);
25
28
  assert.deepStrictEqual(inspect(parser('#(a)')), [['#'], '(a)']);
26
29
  assert.deepStrictEqual(inspect(parser('#{}')), [['#'], '{}']);
27
30
  assert.deepStrictEqual(inspect(parser('#{{}')), [['#'], '{{}']);
@@ -55,16 +58,14 @@ describe('Unit: parser/inline/autolink/hashtag', () => {
55
58
  assert.deepStrictEqual(inspect(parser('#1a')), [['<a class="hashtag" href="/hashtags/1a">#1a</a>'], '']);
56
59
  assert.deepStrictEqual(inspect(parser('#1あ')), [['<a class="hashtag" href="/hashtags/1あ">#1あ</a>'], '']);
57
60
  assert.deepStrictEqual(inspect(parser('#1👩')), [['<a class="hashtag" href="/hashtags/1👩">#1👩</a>'], '']);
58
- assert.deepStrictEqual(inspect(parser(`#'0`)), [[`<a class="hashtag" href="/hashtags/'0">#'0</a>`], '']);
59
- assert.deepStrictEqual(inspect(parser(`#'00`)), [[`<a class="hashtag" href="/hashtags/'00">#'00</a>`], '']);
60
61
  assert.deepStrictEqual(inspect(parser(`#1'`)), [[`<a class="hashtag" href="/hashtags/1'">#1'</a>`], '']);
61
- assert.deepStrictEqual(inspect(parser(`#1''`)), [[`<a class="hashtag" href="/hashtags/1'">#1'</a>`], `'`]);
62
+ assert.deepStrictEqual(inspect(parser(`#1''`)), [[`<a class="hashtag" href="/hashtags/1''">#1''</a>`], '']);
62
63
  assert.deepStrictEqual(inspect(parser(`#a'`)), [[`<a class="hashtag" href="/hashtags/a'">#a'</a>`], '']);
63
- assert.deepStrictEqual(inspect(parser(`#a''`)), [[`<a class="hashtag" href="/hashtags/a'">#a'</a>`], `'`]);
64
+ assert.deepStrictEqual(inspect(parser(`#a''`)), [[`<a class="hashtag" href="/hashtags/a''">#a''</a>`], '']);
64
65
  assert.deepStrictEqual(inspect(parser(`#a'b`)), [[`<a class="hashtag" href="/hashtags/a'b">#a'b</a>`], '']);
65
66
  assert.deepStrictEqual(inspect(parser(`#a'_b`)), [[`<a class="hashtag" href="/hashtags/a'_b">#a'_b</a>`], '']);
66
67
  assert.deepStrictEqual(inspect(parser(`#a_'b`)), [[`<a class="hashtag" href="/hashtags/a_'b">#a_'b</a>`], '']);
67
- assert.deepStrictEqual(inspect(parser(`#${'1'.repeat(15)}a`)), [[`<a class="hashtag" href="/hashtags/${'1'.repeat(15)}a">#${'1'.repeat(15)}a</a>`], '']);
68
+ assert.deepStrictEqual(inspect(parser(`#${'1'.repeat(9)}a`)), [[`<a class="hashtag" href="/hashtags/${'1'.repeat(9)}a">#${'1'.repeat(9)}a</a>`], '']);
68
69
  });
69
70
 
70
71
  });
@@ -15,8 +15,8 @@ export const hashtag: AutolinkParser.HashtagParser = lazy(() => fmap(rewrite(
15
15
  open(
16
16
  '#',
17
17
  str(new RegExp([
18
- /^(?=(?:[0-9]{1,15})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'))/u.source,
19
- /(?:[^\p{C}\p{S}\p{P}\s]|emoji|(?<!')'|_(?=[^\p{C}\p{S}\p{P}\s]|emoji|'))+/u.source,
18
+ /^(?!['_])(?=(?:[0-9]{1,9})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'|_(?=[^\p{C}\p{S}\p{P}\s]|emoji|')))/u.source,
19
+ /(?:[^\p{C}\p{S}\p{P}\s]|emoji|'|_(?=[^\p{C}\p{S}\p{P}\s]|emoji|'))+/u.source,
20
20
  ].join('').replace(/emoji/g, emoji), 'u')))),
21
21
  convert(
22
22
  source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`,
@@ -1,5 +1,5 @@
1
1
  import { AutolinkParser } from '../inline';
2
- import { union, some, syntax, constraint, validate, focus, lazy, fmap } from '../../combinator';
2
+ import { union, some, syntax, constraint, validate, lazy, fmap } from '../../combinator';
3
3
  import { url, lineurl } from './autolink/url';
4
4
  import { email } from './autolink/email';
5
5
  import { channel } from './autolink/channel';
@@ -12,7 +12,7 @@ import { Syntax, State } from '../context';
12
12
  import { stringify } from '../util';
13
13
 
14
14
  export const autolink: AutolinkParser = lazy(() =>
15
- validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i,
15
+ validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/iu,
16
16
  constraint(State.autolink, false,
17
17
  syntax(Syntax.autolink, 1, 1, ~State.shortcut,
18
18
  union([
@@ -21,24 +21,17 @@ export const autolink: AutolinkParser = lazy(() =>
21
21
  url,
22
22
  email,
23
23
  // Escape unmatched email-like strings.
24
- focus(
25
- /^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i,
26
- ({ source }) => {
27
- if (source.length > 255 || source.includes('@')) return [[source], ''];
28
- const i = source.indexOf('_');
29
- if (i === -1) return [[source], ''];
30
- return [[source.slice(0, i)], source.slice(i)];
31
- }),
24
+ str(/^[0-9a-z]+(?:[_.+-][0-9a-z]+)*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i),
32
25
  channel,
33
26
  account,
34
27
  // Escape unmatched account-like strings.
35
- str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
28
+ str(/^@+[0-9a-z]*(?:[-.][0-9a-z]+)*/i),
36
29
  // Escape invalid leading characters.
37
- str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
30
+ str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])(?=#)/u.source.replace('emoji', emoji), 'u')),
38
31
  hashtag,
39
32
  hashnum,
40
33
  // Escape unmatched hashtag-like strings.
41
- str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
34
+ str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])*/u.source.replace('emoji', emoji), 'u')),
42
35
  // Escape invalid leading characters.
43
36
  str(/^[0-9\p{Sc}](?=>)/u),
44
37
  anchor,
@@ -37,8 +37,8 @@ describe('Unit: parser/inline/deletion', () => {
37
37
  });
38
38
 
39
39
  it('nest', () => {
40
- assert.deepStrictEqual(inspect(parser('~~_~~a~~_~~')), [['<del><em><del>a</del></em></del>'], '']);
41
- assert.deepStrictEqual(inspect(parser('~~_++a++_~~')), [['<del><em><ins>a</ins></em></del>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('~~*~~a~~*~~')), [['<del><em><del>a</del></em></del>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('~~*++a++*~~')), [['<del><em><ins>a</ins></em></del>'], '']);
42
42
  });
43
43
 
44
44
  });
@@ -7,38 +7,47 @@ describe('Unit: parser/inline/emphasis', () => {
7
7
  const parser = (source: string) => some(emphasis)({ source, context: {} });
8
8
 
9
9
  it('invalid', () => {
10
- assert.deepStrictEqual(inspect(parser('_')), undefined);
11
- assert.deepStrictEqual(inspect(parser('_a')), [['_', 'a'], '']);
12
- assert.deepStrictEqual(inspect(parser('_a _')), [['_', 'a'], ' _']);
13
- assert.deepStrictEqual(inspect(parser('_a _')), [['_', 'a', ' '], ' _']);
14
- assert.deepStrictEqual(inspect(parser('_a\n_')), [['_', 'a'], '\n_']);
15
- assert.deepStrictEqual(inspect(parser('_a\nb_')), [['_', 'a'], '\nb_']);
16
- assert.deepStrictEqual(inspect(parser('_a\\ _')), [['_', 'a'], '\\ _']);
17
- assert.deepStrictEqual(inspect(parser('_a\\\n_')), [['_', 'a'], '\\\n_']);
18
- assert.deepStrictEqual(inspect(parser('_a\\\nb_')), [['_', 'a'], '\\\nb_']);
19
- assert.deepStrictEqual(inspect(parser('_ _')), undefined);
20
- assert.deepStrictEqual(inspect(parser('_ a_')), undefined);
21
- assert.deepStrictEqual(inspect(parser('_ a _')), undefined);
22
- assert.deepStrictEqual(inspect(parser('_\n_')), undefined);
23
- assert.deepStrictEqual(inspect(parser('_\na_')), undefined);
24
- assert.deepStrictEqual(inspect(parser('_\\ a_')), undefined);
25
- assert.deepStrictEqual(inspect(parser('_\\\na_')), undefined);
26
- assert.deepStrictEqual(inspect(parser('_<wbr>a_')), undefined);
27
- assert.deepStrictEqual(inspect(parser(' _a_')), undefined);
10
+ assert.deepStrictEqual(inspect(parser('*')), undefined);
11
+ assert.deepStrictEqual(inspect(parser('*a')), [['*', 'a'], '']);
12
+ assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a'], ' *']);
13
+ assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a', ' '], ' *']);
14
+ assert.deepStrictEqual(inspect(parser('*a\n*')), [['*', 'a'], '\n*']);
15
+ assert.deepStrictEqual(inspect(parser('*a\nb*')), [['*', 'a'], '\nb*']);
16
+ assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a'], '\\ *']);
17
+ assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a'], '\\\n*']);
18
+ assert.deepStrictEqual(inspect(parser('*a\\\nb*')), [['*', 'a'], '\\\nb*']);
19
+ assert.deepStrictEqual(inspect(parser('*a**b')), [['*', 'a', '**', 'b'], '']);
20
+ assert.deepStrictEqual(inspect(parser('*a**b*')), [['*', 'a', '**', 'b', '*'], '']);
21
+ assert.deepStrictEqual(inspect(parser('* *')), undefined);
22
+ assert.deepStrictEqual(inspect(parser('* a*')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('* a *')), undefined);
24
+ assert.deepStrictEqual(inspect(parser('*\n*')), undefined);
25
+ assert.deepStrictEqual(inspect(parser('*\na*')), undefined);
26
+ assert.deepStrictEqual(inspect(parser('*\\ a*')), undefined);
27
+ assert.deepStrictEqual(inspect(parser('*\\\na*')), undefined);
28
+ assert.deepStrictEqual(inspect(parser('*<wbr>a*')), undefined);
29
+ assert.deepStrictEqual(inspect(parser('**a**')), undefined);
30
+ assert.deepStrictEqual(inspect(parser('***a***')), undefined);
31
+ assert.deepStrictEqual(inspect(parser(' *a*')), undefined);
28
32
  });
29
33
 
30
34
  it('basic', () => {
31
- assert.deepStrictEqual(inspect(parser('_a_')), [['<em>a</em>'], '']);
32
- assert.deepStrictEqual(inspect(parser('_ab_')), [['<em>ab</em>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('*a*')), [['<em>a</em>'], '']);
36
+ assert.deepStrictEqual(inspect(parser('*ab*')), [['<em>ab</em>'], '']);
37
+ assert.deepStrictEqual(inspect(parser('*a**')), [['<em>a</em>'], '*']);
33
38
  });
34
39
 
35
40
  it('nest', () => {
36
- assert.deepStrictEqual(inspect(parser('_a _b__')), [['<em>a <em>b</em></em>'], '']);
37
- assert.deepStrictEqual(inspect(parser('_a *b*_')), [['<em>a <strong>b</strong></em>'], '']);
38
- assert.deepStrictEqual(inspect(parser('_a\\ _b__')), [['<em>a <em>b</em></em>'], '']);
39
- assert.deepStrictEqual(inspect(parser('_a&Tab;_b__')), [['<em>a\t<em>b</em></em>'], '']);
40
- assert.deepStrictEqual(inspect(parser('_a<wbr>_b__')), [['<em>a<wbr><em>b</em></em>'], '']);
41
- assert.deepStrictEqual(inspect(parser('_(_a_)_')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('*a *b**')), [['<em>a <em>b</em></em>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('*a **b***')), [['<em>a <strong>b</strong></em>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('*a\\ *b**')), [['<em>a <em>b</em></em>'], '']);
44
+ assert.deepStrictEqual(inspect(parser('*a&Tab;*b**')), [['<em>a\t<em>b</em></em>'], '']);
45
+ assert.deepStrictEqual(inspect(parser('*a<wbr>*b**')), [['<em>a<wbr><em>b</em></em>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('*a**b**c*')), [['<em>a<strong>b</strong>c</em>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('*a**b**c*d')), [['<em>a<strong>b</strong>c</em>'], 'd']);
48
+ assert.deepStrictEqual(inspect(parser('*`a`*')), [['<em><code data-src="`a`">a</code></em>'], '']);
49
+ assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('*(**a**)*')), [['<em><span class="paren">(<strong>a</strong>)</span></em>'], '']);
42
51
  });
43
52
 
44
53
  });
@@ -1,6 +1,8 @@
1
1
  import { EmphasisParser } from '../inline';
2
2
  import { union, some, syntax, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
+ import { emstrong } from './emstrong';
5
+ import { strong } from './strong';
4
6
  import { str } from '../source';
5
7
  import { Syntax, State } from '../context';
6
8
  import { startTight, blankWith } from '../visibility';
@@ -8,12 +10,17 @@ import { unshift } from 'spica/array';
8
10
  import { html, defrag } from 'typed-dom/dom';
9
11
 
10
12
  export const emphasis: EmphasisParser = lazy(() => surround(
11
- str('_', '_'),
13
+ str('*', '*'),
12
14
  syntax(Syntax.none, 1, 1, State.none,
13
15
  startTight(some(union([
14
- some(inline, blankWith('_'), [[/^\\?\n/, 9]]),
15
- open(some(inline, '_', [[/^\\?\n/, 9]]), emphasis),
16
+ strong,
17
+ some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
18
+ open(some(inline, '*', [[/^\\?\n/, 9]]), union([
19
+ emstrong,
20
+ strong,
21
+ emphasis,
22
+ ])),
16
23
  ])))),
17
- str('_'), false,
24
+ str('*'), false,
18
25
  ([, bs], rest) => [[html('em', defrag(bs))], rest],
19
26
  ([as, bs], rest) => [unshift(as, bs), rest]));
@@ -0,0 +1,62 @@
1
+ import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
2
+ import { Result, IntermediateParser } from '../../combinator/data/parser';
3
+ import { union, syntax, some, surround, open, lazy, bind } from '../../combinator';
4
+ import { inline } from '../inline';
5
+ import { strong } from './strong';
6
+ import { emphasis } from './emphasis';
7
+ import { str } from '../source';
8
+ import { Syntax, State } from '../context';
9
+ import { startTight, blankWith } from '../visibility';
10
+ import { html, defrag } from 'typed-dom/dom';
11
+ import { unshift } from 'spica/array';
12
+
13
+ const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
14
+ some(inline, blankWith('**'), [[/^\\?\n/, 9]]),
15
+ open(some(inline, '*', [[/^\\?\n/, 9]]), union([
16
+ emstrong,
17
+ strong,
18
+ ])),
19
+ ])));
20
+ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
21
+ strong,
22
+ some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
23
+ open(some(inline, '*', [[/^\\?\n/, 9]]), union([
24
+ emstrong,
25
+ strong,
26
+ emphasis,
27
+ ])),
28
+ ])));
29
+
30
+ export const emstrong: EmStrongParser = lazy(() => surround(
31
+ str('***'),
32
+ syntax(Syntax.none, 1, 1, State.none,
33
+ startTight(some(union([
34
+ some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
35
+ open(some(inline, '*', [[/^\\?\n/, 9]]), inline),
36
+ ])))),
37
+ str(/^\*{1,3}/), false,
38
+ ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
39
+ assert(cs.length === 1);
40
+ switch (cs[0]) {
41
+ case '***':
42
+ return [[html('em', [html('strong', defrag(bs))])], rest];
43
+ case '**':
44
+ return bind<EmphasisParser>(
45
+ subemphasis,
46
+ (ds, rest) =>
47
+ rest.slice(0, 1) === '*'
48
+ ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds)))], rest.slice(1)]
49
+ : [unshift(['*', html('strong', defrag(bs))], ds), rest])
50
+ ({ source: rest, context }) ?? [['*', html('strong', defrag(bs))], rest];
51
+ case '*':
52
+ return bind<StrongParser>(
53
+ substrong,
54
+ (ds, rest) =>
55
+ rest.slice(0, 2) === '**'
56
+ ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
57
+ : [unshift(['**', html('em', defrag(bs))], ds), rest])
58
+ ({ source: rest, context }) ?? [['**', html('em', defrag(bs))], rest];
59
+ }
60
+ assert(false);
61
+ },
62
+ ([as, bs], rest) => [unshift(as, bs), rest]));
@@ -43,7 +43,7 @@ describe('Unit: parser/inline/extension/index', () => {
43
43
  assert.deepStrictEqual(inspect(parser('[#a \\ ]')), [['<a class="index" href="#index::a">a</a>'], '']);
44
44
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;]')), [['<a class="index" href="#index::a">a</a>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser('[#a <wbr>]')), [['<a class="index" href="#index::a">a</a>'], '']);
46
- assert.deepStrictEqual(inspect(parser('[#a [% b %]]')), [['<a class="index" href="#index::a">a <span class="comment"><input type="checkbox"><span>[% b %]</span></span></a>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('[#a [% b %]]')), [['<a class="index" href="#index::a">a <span class="remark"><input type="checkbox"><span>[% b %]</span></span></a>'], '']);
47
47
  assert.deepStrictEqual(inspect(parser('[#a\\ ]')), [['<a class="index" href="#index::a">a</a>'], '']);
48
48
  assert.deepStrictEqual(inspect(parser('[#a\\ b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('[#[]]')), [['<a class="index" href="#index::[]">[]</a>'], '']);
@@ -51,7 +51,7 @@ describe('Unit: parser/inline/extension/index', () => {
51
51
  assert.deepStrictEqual(inspect(parser('[#\\\\]')), [['<a class="index" href="#index::\\">\\</a>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser('[#A]')), [['<a class="index" href="#index::A">A</a>'], '']);
53
53
  assert.deepStrictEqual(inspect(parser('[#==]')), [['<a class="index" href="#index::==">==</a>'], '']);
54
- assert.deepStrictEqual(inspect(parser('[#_A_]')), [['<a class="index" href="#index::A"><em>A</em></a>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('[#*A*]')), [['<a class="index" href="#index::A"><em>A</em></a>'], '']);
55
55
  assert.deepStrictEqual(inspect(parser('[#`A`]')), [['<a class="index" href="#index::`A`"><code data-src="`A`">A</code></a>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('[#${A}$]')), [['<a class="index" href="#index::${A}$"><span class="math" translate="no" data-src="${A}$">${A}$</span></a>'], '']);
57
57
  assert.deepStrictEqual(inspect(parser('[#[A](a)]')), [['<a class="index" href="#index::A"><ruby>A<rp>(</rp><rt>a</rt><rp>)</rp></ruby></a>'], '']);
@@ -60,8 +60,8 @@ describe('Unit: parser/inline/extension/index', () => {
60
60
  assert.deepStrictEqual(inspect(parser('[#@a]')), [['<a class="index" href="#index::@a">@a</a>'], '']);
61
61
  assert.deepStrictEqual(inspect(parser('[#http://host]')), [['<a class="index" href="#index::http://host">http://host</a>'], '']);
62
62
  assert.deepStrictEqual(inspect(parser('[#!http://host]')), [['<a class="index" href="#index::!http://host">!http://host</a>'], '']);
63
- assert.deepStrictEqual(inspect(parser('[#[% %]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[% %]</span></span></a>'], '']);
64
- assert.deepStrictEqual(inspect(parser('[#[% a %]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></a>'], '']);
63
+ assert.deepStrictEqual(inspect(parser('[#[% %]]')), [['<a class="index"><span class="remark"><input type="checkbox"><span>[% %]</span></span></a>'], '']);
64
+ assert.deepStrictEqual(inspect(parser('[#[% a %]]')), [['<a class="index"><span class="remark"><input type="checkbox"><span>[% a %]</span></span></a>'], '']);
65
65
  assert.deepStrictEqual(inspect(parser('[#a((b))]')), [['<a class="index" href="#index::a((b))">a<span class="paren">((b))</span></a>'], '']);
66
66
  assert.deepStrictEqual(inspect(parser('[#a[[b]]]')), [['<a class="index" href="#index::a[[b]]">a[[b]]</a>'], '']);
67
67
  });
@@ -76,7 +76,7 @@ describe('Unit: parser/inline/extension/index', () => {
76
76
  assert.deepStrictEqual(inspect(parser('[#a|b ]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
77
77
  assert.deepStrictEqual(inspect(parser('[#a|b ]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
78
78
  assert.deepStrictEqual(inspect(parser('[#a|\\b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
79
- assert.deepStrictEqual(inspect(parser('[#a|_b_]')), [['<a class="index" href="#index::_b_">a<span class="indexer" data-index="_b_"></span></a>'], '']);
79
+ assert.deepStrictEqual(inspect(parser('[#a|*b*]')), [['<a class="index" href="#index::*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
80
80
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
81
81
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
82
82
  assert.deepStrictEqual(inspect(parser('[#a|[]]')), [['<a class="index" href="#index::[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
@@ -86,7 +86,7 @@ describe('Unit: parser/inline/extension/index', () => {
86
86
  assert.deepStrictEqual(inspect(parser('[#a \\ |b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
87
87
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;|b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
88
88
  assert.deepStrictEqual(inspect(parser('[#a <wbr>|b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
89
- assert.deepStrictEqual(inspect(parser('[#a [% b %]|c]')), [['<a class="index" href="#index::c">a <span class="comment"><input type="checkbox"><span>[% b %]</span></span><span class="indexer" data-index="c"></span></a>'], '']);
89
+ assert.deepStrictEqual(inspect(parser('[#a [% b %]|c]')), [['<a class="index" href="#index::c">a <span class="remark"><input type="checkbox"><span>[% b %]</span></span><span class="indexer" data-index="c"></span></a>'], '']);
90
90
  assert.deepStrictEqual(inspect(parser('[#a\\ |b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
91
91
  });
92
92
 
@@ -34,7 +34,7 @@ assert(identity(undefined, '0'.repeat(41) + '1'.repeat(38) + '2'.repeat(41) + 3,
34
34
  assert(identity(undefined, '0'.repeat(81) + '1'.repeat(38) + '2'.repeat(81) + 3, 'mark')!.slice(6) === '0'.repeat(38) + '...' + '1'.repeat(38) + '...' + '2'.repeat(38 - 1) + 3);
35
35
 
36
36
  export function index(source: Element, optional = false): string {
37
- assert(source instanceof DocumentFragment || !source.matches('.indexer'));
37
+ assert(!source.matches('.indexer'));
38
38
  assert(source.querySelectorAll(':scope > .indexer').length <= 1);
39
39
  if (!source.firstChild) return '';
40
40
  const indexer = source.querySelector(':scope > .indexer');
@@ -47,7 +47,7 @@ export function index(source: Element, optional = false): string {
47
47
  export function signature(source: Element | DocumentFragment): string {
48
48
  assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))'));
49
49
  const target = source.cloneNode(true) as typeof source;
50
- for (let es = target.querySelectorAll('code[data-src], .math[data-src], .label[data-label], .comment, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
50
+ for (let es = target.querySelectorAll('code[data-src], .math[data-src], .label[data-label], .remark, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
51
51
  len = es.length, i = 0; i < len; ++i) {
52
52
  const el = es[i];
53
53
  switch (el.tagName) {
@@ -69,7 +69,7 @@ export function signature(source: Element | DocumentFragment): string {
69
69
  case 'label':
70
70
  el.replaceWith(`[$${el.getAttribute('data-label')!.replace('$', '')}]`);
71
71
  continue;
72
- case 'comment':
72
+ case 'remark':
73
73
  case 'checkbox':
74
74
  case 'annotation':
75
75
  case 'reference':
@@ -83,7 +83,7 @@ export function signature(source: Element | DocumentFragment): string {
83
83
  export const text = reduce((source: Element | DocumentFragment): string => {
84
84
  assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))'));
85
85
  const target = source.cloneNode(true) as typeof source;
86
- for (let es = target.querySelectorAll('code[data-src], .math[data-src], .comment, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
86
+ for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
87
87
  len = es.length, i = 0; i < len; ++i) {
88
88
  const el = es[i];
89
89
  switch (el.tagName) {
@@ -102,7 +102,7 @@ export const text = reduce((source: Element | DocumentFragment): string => {
102
102
  case 'math':
103
103
  el.replaceWith(el.getAttribute('data-src')!);
104
104
  continue;
105
- case 'comment':
105
+ case 'remark':
106
106
  case 'checkbox':
107
107
  case 'annotation':
108
108
  case 'reference':
@@ -44,13 +44,13 @@ describe('Unit: parser/inline/extension/placeholder', () => {
44
44
  assert.deepStrictEqual(inspect(parser('[^a<wbr>]')), [['<span class="invalid">a<wbr></span>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser('[^a<wbr><wbr>]')), [['<span class="invalid">a<wbr><wbr></span>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser('[^==]')), [['<span class="invalid">==</span>'], '']);
47
- assert.deepStrictEqual(inspect(parser('[^a[% b %]]')), [['<span class="invalid">a<span class="comment"><input type="checkbox"><span>[% b %]</span></span></span>'], '']);
48
- assert.deepStrictEqual(inspect(parser('[^a[% b %][% c %]]')), [['<span class="invalid">a<span class="comment"><input type="checkbox"><span>[% b %]</span></span><span class="comment"><input type="checkbox"><span>[% c %]</span></span></span>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('[^a[% b %]]')), [['<span class="invalid">a<span class="remark"><input type="checkbox"><span>[% b %]</span></span></span>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('[^a[% b %][% c %]]')), [['<span class="invalid">a<span class="remark"><input type="checkbox"><span>[% b %]</span></span><span class="remark"><input type="checkbox"><span>[% c %]</span></span></span>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('[^\\]]')), [['<span class="invalid">]</span>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser('[^(])]')), [['<span class="invalid"><span class="paren">(])</span></span>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid">!<a class="url" href="http://host" target="_blank">http://host</a></span>'], '']);
52
- assert.deepStrictEqual(inspect(parser('[^[% a %]]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></span>'], '']);
53
- assert.deepStrictEqual(inspect(parser('[^[% a %]b]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span>b</span>'], '']);
52
+ assert.deepStrictEqual(inspect(parser('[^[% a %]]')), [['<span class="invalid"><span class="remark"><input type="checkbox"><span>[% a %]</span></span></span>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('[^[% a %]b]')), [['<span class="invalid"><span class="remark"><input type="checkbox"><span>[% a %]</span></span>b</span>'], '']);
54
54
  });
55
55
 
56
56
  });
@@ -37,8 +37,8 @@ describe('Unit: parser/inline/insertion', () => {
37
37
  });
38
38
 
39
39
  it('nest', () => {
40
- assert.deepStrictEqual(inspect(parser('++_++a++_++')), [['<ins><em><ins>a</ins></em></ins>'], '']);
41
- assert.deepStrictEqual(inspect(parser('++_~~a~~_++')), [['<ins><em><del>a</del></em></ins>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('++*++a++*++')), [['<ins><em><ins>a</ins></em></ins>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('++*~~a~~*++')), [['<ins><em><del>a</del></em></ins>'], '']);
42
42
  });
43
43
 
44
44
  });
@@ -175,7 +175,7 @@ describe('Unit: parser/inline/link', () => {
175
175
  assert.deepStrictEqual(inspect(parser('[@a]{b}')), [['<a class="link" href="b">@a</a>'], '']);
176
176
  assert.deepStrictEqual(inspect(parser('[@a@b]{c}')), [['<a class="link" href="c">@a@b</a>'], '']);
177
177
  assert.deepStrictEqual(inspect(parser('[a@b]{c}')), [['<a class="link" href="c">a@b</a>'], '']);
178
- assert.deepStrictEqual(inspect(parser('[*a*]{b}')), [['<a class="link" href="b"><strong>a</strong></a>'], '']);
178
+ assert.deepStrictEqual(inspect(parser('[*a*]{b}')), [['<a class="link" href="b"><em>a</em></a>'], '']);
179
179
  });
180
180
 
181
181
  it('external', () => {
@@ -203,10 +203,10 @@ export function resolve(uri: string, host: URL | Location, source: URL | Locatio
203
203
 
204
204
  function decode(uri: string): string {
205
205
  if (!uri.includes('%')) return uri;
206
- const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
206
+ const origin = uri.match(/^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
207
207
  try {
208
208
  let path = decodeURI(uri.slice(origin.length));
209
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
209
+ if (!origin && /^[a-z](?:[-.](?=[0-9a-z])|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
210
210
  path = uri.slice(origin.length);
211
211
  }
212
212
  uri = origin + path;
@@ -40,7 +40,7 @@ describe('Unit: parser/inline/mark', () => {
40
40
  assert.deepStrictEqual(inspect(parser('==a\\ ==b====')), [['<mark id="mark::a_b">a <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
41
41
  assert.deepStrictEqual(inspect(parser('==a&Tab;==b====')), [['<mark id="mark::a_b">a\t<mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
42
42
  assert.deepStrictEqual(inspect(parser('==a<wbr>==b====')), [['<mark id="mark::ab">a<wbr><mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::ab"></a>'], '']);
43
- assert.deepStrictEqual(inspect(parser('==_==a==_==')), [['<mark id="mark::a"><em><mark id="mark::a">a</mark><a href="#mark::a"></a></em></mark>', '<a href="#mark::a"></a>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('==*==a==*==')), [['<mark id="mark::a"><em><mark id="mark::a">a</mark><a href="#mark::a"></a></em></mark>', '<a href="#mark::a"></a>'], '']);
44
44
  });
45
45
 
46
46
  });