securemark 0.268.2 → 0.269.1

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.
@@ -96,7 +96,7 @@ describe('Unit: parser/block/blockquote', () => {
96
96
  assert.deepStrictEqual(inspect(parser('!>> ## a\n> ## a')), [['<blockquote><blockquote><section><h2>a</h2><h2>References</h2><ol class="references"></ol></section></blockquote><section><h2>a</h2><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
97
97
  assert.deepStrictEqual(inspect(parser('!>> ~ a\n> ~ a')), [['<blockquote><blockquote><section><dl><dt>a</dt><dd></dd></dl><h2>References</h2><ol class="references"></ol></section></blockquote><section><dl><dt>a</dt><dd></dd></dl><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
98
98
  assert.deepStrictEqual(inspect(parser('!>> ~~~figure $test-a\n>> > \n>>\n~~~\n> ~~~figure $test-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"><a class="index">a</a></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
99
- assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
99
+ assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
100
100
  });
101
101
 
102
102
  });
@@ -23,7 +23,7 @@ describe('Unit: parser/block/extension/example', () => {
23
23
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n[$fig-a]\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">[$fig-a]\n!https://host</pre><hr><section><figure data-type="media" data-label="fig-a" data-group="fig" data-number="1"><figcaption><span class="figindex">Fig. 1. </span><span class="figtext"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n## a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">## a</pre><hr><section><h2>a</h2><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
25
25
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n~ a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">~ a</pre><hr><section><dl><dt>a</dt><dd></dd></dl><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
26
- assert.deepStrictEqual(inspect(parser('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><sup class="reference disabled" title="b"><span hidden="">b</span><a>[1]</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"><li>b<sup><a>^1</a></sup></li></ol></section></aside>'], '']);
26
+ assert.deepStrictEqual(inspect(parser('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><sup class="reference disabled" title="b"><span hidden="">b</span><a>[1]</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"><li><span>b</span><sup><a>^1</a></sup></li></ol></section></aside>'], '']);
27
27
  assert.deepStrictEqual(inspect(parser('~~~~example/markdown\na\n~~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">a</pre><hr><section><p>a</p><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
28
28
  assert.deepStrictEqual(inspect(parser('~~~example/math\na\n~~~')), [['<aside class="example" data-type="math"><pre translate="no">a</pre><hr><div class="math" translate="no">$$\na\n$$</div></aside>'], '']);
29
29
  assert.deepStrictEqual(inspect(parser(`~~~example/math\n0${'\n'.repeat(100)}~~~`), '>'), [['<aside class="example" data-type="math">'], '']);
@@ -30,9 +30,11 @@ describe('Unit: parser/block/paragraph', () => {
30
30
  assert.deepStrictEqual(inspect(parser('_a\n<wbr>_\nb')), [['<p>_a<br><wbr>_<br>b</p>'], '']);
31
31
  assert.deepStrictEqual(inspect(parser('*a\n<wbr>*\nb')), [['<p>*a<br><wbr>*<br>b</p>'], '']);
32
32
  assert.deepStrictEqual(inspect(parser('==a\n<wbr>==\nb')), [['<p>==a<br><wbr>==<br>b</p>'], '']);
33
- assert.deepStrictEqual(inspect(parser('http://host#!')), [['<p><a class="url" href="http://host#!" target="_blank">http://host#!</a></p>'], '']);
33
+ assert.deepStrictEqual(inspect(parser('http://host#\\')), [['<p><a class="url" href="http://host#\\" target="_blank">http://host#\\</a></p>'], '']);
34
34
  assert.deepStrictEqual(inspect(parser('a\nhttp://host#\\ \nb')), [['<p>a<br><a class="url" href="http://host#\\" target="_blank">http://host#\\</a><br>b</p>'], '']);
35
- assert.deepStrictEqual(inspect(parser('!http://host#!')), [['<p><a href="http://host#!" target="_blank"><img class="media" data-src="http://host#!" alt=""></a></p>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('!http://host#\\')), [['<p><a href="http://host#\\" target="_blank"><img class="media" data-src="http://host#\\" alt=""></a></p>'], '']);
36
+ assert.deepStrictEqual(inspect(parser('!http://host#\\ a')), [['<p>!<a class="url" href="http://host#" target="_blank">http://host#</a> a</p>'], '']);
37
+ assert.deepStrictEqual(inspect(parser(' !http://host#\\')), [['<p> !<a class="url" href="http://host#" target="_blank">http://host#</a></p>'], '']);
36
38
  assert.deepStrictEqual(inspect(parser('\ta')), [['<p>\ta</p>'], '']);
37
39
  });
38
40
 
@@ -1,9 +1,10 @@
1
1
  import { ParagraphParser } from '../block';
2
- import { union, some, block, trimEnd, fmap } from '../../combinator';
2
+ import { union, some, block, convert, trimEnd, fmap } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { visualize } from '../visibility';
5
5
  import { html, defrag } from 'typed-dom/dom';
6
6
 
7
7
  export const paragraph: ParagraphParser = block(fmap(
8
- visualize(trimEnd(some(union([inline])))),
8
+ convert(source => `\r${source}`,
9
+ visualize(trimEnd(some(union([inline]))))),
9
10
  ns => [html('p', defrag(ns))]));
@@ -55,9 +55,9 @@ describe('Unit: parser/block/reply/quote', () => {
55
55
  assert.deepStrictEqual(inspect(parser('> $-a, $-b')), [['<span class="quote">&gt; $-a, $-b</span>', '<br>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('> $a=b$')), [['<span class="quote">&gt; <span class="math" translate="no" data-src="$a=b$">$a=b$</span></span>', '<br>'], '']);
57
57
  assert.deepStrictEqual(inspect(parser('> ${a}$')), [['<span class="quote">&gt; <span class="math" translate="no" data-src="${a}$">${a}$</span></span>', '<br>'], '']);
58
- assert.deepStrictEqual(inspect(parser('> http://host#!')), [['<span class="quote">&gt; <a class="url" href="http://host#!" target="_blank">http://host#!</a></span>', '<br>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('> http://host#\\')), [['<span class="quote">&gt; <a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
59
59
  assert.deepStrictEqual(inspect(parser('> a\n> http://host#\\ \n> b')), [['<span class="quote">&gt; a<br>&gt; <a class="url" href="http://host#\\" target="_blank">http://host#\\</a> <br>&gt; b</span>', '<br>'], '']);
60
- assert.deepStrictEqual(inspect(parser('> !http://host#!')), [['<span class="quote">&gt; !<a class="url" href="http://host#!" target="_blank">http://host#!</a></span>', '<br>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('> !http://host#\\')), [['<span class="quote">&gt; !<a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
61
61
  });
62
62
 
63
63
  });
@@ -1,10 +1,9 @@
1
1
  import { ReplyParser } from '../../block';
2
2
  import { eval } from '../../../combinator/data/parser';
3
- import { union, subsequence, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
3
+ import { union, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
4
4
  import { math } from '../../inline/math';
5
5
  import { autolink } from '../../inline/autolink';
6
6
  import { linebreak, unescsource, str, anyline } from '../../source';
7
- import { lineurl } from '../../autolink';
8
7
  import { html, defrag } from 'typed-dom/dom';
9
8
 
10
9
  export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
@@ -42,7 +41,7 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
42
41
  assert(quotes);
43
42
  assert(quotes.length > 0);
44
43
  const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
45
- const nodes = eval(text({ source: content, context }), []);
44
+ const nodes = eval(text({ source: `\r${content}`, context }), []);
46
45
  nodes.unshift(quotes.shift()!);
47
46
  for (let i = 0; i < nodes.length; ++i) {
48
47
  const child = nodes[i] as string | Text | Element;
@@ -72,12 +71,9 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
72
71
  return [nodes, ''];
73
72
  };
74
73
 
75
- const text: ReplyParser.QuoteParser.TextParser = some(line(subsequence([
76
- lineurl,
77
- some(union([
78
- math, // quote補助関数が残した数式をパースする。他の構文で数式を残す場合はソーステキストを直接使用する。
79
- autolink,
80
- linebreak,
81
- unescsource,
82
- ])),
83
- ])));
74
+ const text: ReplyParser.QuoteParser.TextParser = some(union([
75
+ math, // quote補助関数が残した数式をパースする。他の構文で数式を残す場合はソーステキストを直接使用する。
76
+ autolink,
77
+ linebreak,
78
+ unescsource,
79
+ ]));
@@ -28,6 +28,8 @@ describe('Unit: parser/inline/autolink/url', () => {
28
28
  assert.deepStrictEqual(inspect(parser('http://a#( )')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '( )']);
29
29
  assert.deepStrictEqual(inspect(parser('http://a#(\n)')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '(\n)']);
30
30
  assert.deepStrictEqual(inspect(parser('http://[::]')), [['<a class="url" href="http://[::]" target="_blank">http://[::]</a>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('\rhttp://a#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>'], '']);
32
+ assert.deepStrictEqual(inspect(parser('\rhttp://a#\\\nhttp://b#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>', '<br>', '<a class="url" href="http://b#\\" target="_blank">http://b#\\</a>'], '']);
31
33
  });
32
34
 
33
35
  it('trailing symbols', () => {
@@ -1,7 +1,7 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { union, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
2
+ import { union, tails, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
3
3
  import { unsafelink } from '../link';
4
- import { unescsource } from '../../source';
4
+ import { linebreak, unescsource, str } from '../../source';
5
5
 
6
6
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
7
7
 
@@ -13,6 +13,17 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
13
13
  url => `{ ${url} }`,
14
14
  union([unsafelink])))));
15
15
 
16
+ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = open(
17
+ linebreak,
18
+ tails([
19
+ str('!'),
20
+ focus(
21
+ /^https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
22
+ convert(
23
+ url => `{ ${url} }`,
24
+ unsafelink)),
25
+ ]));
26
+
16
27
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(precedence(2, union([
17
28
  surround('(', some(union([bracket, unescsource]), ')'), ')', true),
18
29
  surround('[', some(union([bracket, unescsource]), ']'), ']', true),
@@ -1,6 +1,6 @@
1
1
  import { AutolinkParser } from '../inline';
2
2
  import { union, some, syntax, constraint, validate, focus, fmap } from '../../combinator';
3
- import { url } from './autolink/url';
3
+ import { url, lineurl } from './autolink/url';
4
4
  import { email } from './autolink/email';
5
5
  import { channel } from './autolink/channel';
6
6
  import { account } from './autolink/account';
@@ -11,34 +11,37 @@ import { str } from '../source';
11
11
  import { Syntax, State } from '../context';
12
12
  import { stringify } from '../util';
13
13
 
14
- export const autolink: AutolinkParser = fmap(
15
- validate(/^(?:[@#>0-9a-z]|\S[#>])/i,
14
+ export const autolink: AutolinkParser =
15
+ validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i,
16
16
  constraint(State.autolink, false,
17
17
  syntax(Syntax.autolink, 1, 1, ~State.shortcut,
18
- some(union([
19
- url,
20
- email,
21
- // Escape unmatched email-like strings.
22
- focus(
23
- /^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i,
24
- ({ source }) => {
25
- if (source.length > 255 || source.includes('@')) return [[source], ''];
26
- const i = source.indexOf('_');
27
- if (i === -1) return [[source], ''];
28
- return [[source.slice(0, i)], source.slice(i)];
29
- }),
30
- channel,
31
- account,
32
- // Escape unmatched account-like strings.
33
- str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
34
- // Escape invalid leading characters.
35
- str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
36
- hashtag,
37
- hashnum,
38
- // Escape unmatched hashtag-like strings.
39
- str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
40
- // Escape invalid leading characters.
41
- str(/^[0-9\p{Sc}](?=>)/u),
42
- anchor,
43
- ]))))),
44
- ns => ns.length === 1 ? ns : [stringify(ns)]);
18
+ union([
19
+ some(union([lineurl])),
20
+ fmap(some(union([
21
+ url,
22
+ email,
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
+ }),
32
+ channel,
33
+ account,
34
+ // Escape unmatched account-like strings.
35
+ str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
36
+ // Escape invalid leading characters.
37
+ str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
38
+ hashtag,
39
+ hashnum,
40
+ // Escape unmatched hashtag-like strings.
41
+ str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
42
+ // Escape invalid leading characters.
43
+ str(/^[0-9\p{Sc}](?=>)/u),
44
+ anchor,
45
+ ])),
46
+ ns => ns.length === 1 ? ns : [stringify(ns)]),
47
+ ]))));
@@ -8,7 +8,7 @@ export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>, opt
8
8
  return fmap(parser, ([el], _, { id }) => [define(el, { id: identity(id, text(el, optional)) })]);
9
9
  }
10
10
 
11
- export function identity(id: string | undefined, text: string, name: 'index' | 'mark' = 'index'): string | undefined {
11
+ export function identity(id: string | undefined, text: string, name: 'index' | 'mark' | 'note' = 'index'): string | undefined {
12
12
  assert(!id?.match(/[^0-9a-z/-]/i));
13
13
  assert(!text.includes('\n'));
14
14
  if (id === '') return undefined;
@@ -20,6 +20,7 @@ export function identity(id: string | undefined, text: string, name: 'index' | '
20
20
  case 'index':
21
21
  return `${name}:${id ?? ''}:${cs.slice(0, 97).join('')}...`;
22
22
  case 'mark':
23
+ case 'note':
23
24
  return `${name}:${id ?? ''}:${cs.slice(0, 50).join('')}...${cs.slice(-47).join('')}`;
24
25
  }
25
26
  assert(false);
@@ -31,7 +32,7 @@ assert(identity(undefined, '0'.repeat(100 - 1) + 1, 'mark')!.slice(6) === '0'.re
31
32
  assert(identity(undefined, '0'.repeat(100) + 1, 'mark')!.slice(6) === '0'.repeat(50) + '...' + '0'.repeat(47 - 1) + 1);
32
33
  assert(identity(undefined, '0'.repeat(200) + 1, 'mark')!.slice(6) === '0'.repeat(50) + '...' + '0'.repeat(47 - 1) + 1);
33
34
 
34
- export function text(source: HTMLElement | DocumentFragment, optional = false): string {
35
+ export function text(source: Element | DocumentFragment, optional = false): string {
35
36
  assert(source instanceof DocumentFragment || !source.matches('.indexer'));
36
37
  assert(source.querySelectorAll(':scope > .indexer').length <= 1);
37
38
  if (!source.firstChild) return '';
@@ -48,7 +48,7 @@ describe('Unit: parser/inline/extension/placeholder', () => {
48
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>'], '']);
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
- assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid"><a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a></span>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid">!<a class="url" href="http://host" target="_blank">http://host</a></span>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser('[^[% a %]]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></span>'], '']);
53
53
  assert.deepStrictEqual(inspect(parser('[^[% a %]b]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span>b</span>'], '']);
54
54
  });
@@ -4,7 +4,7 @@ import { Result } from '../../combinator/data/parser';
4
4
  import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
- import { unescsource, str } from '../source';
7
+ import { linebreak, unescsource, str } from '../source';
8
8
  import { Syntax, State } from '../context';
9
9
  import { trimNode } from '../visibility';
10
10
  import { stringify } from '../util';
@@ -21,7 +21,7 @@ export const link: LinkParser = lazy(() => validate(['[', '{'], union([
21
21
  textlink,
22
22
  ])));
23
23
 
24
- const textlink: LinkParser.TextLinkParser = lazy(() =>
24
+ export const textlink: LinkParser.TextLinkParser = lazy(() =>
25
25
  constraint(State.link, false,
26
26
  syntax(Syntax.link, 2, 10, State.linkers | State.media,
27
27
  bind(reverse(tails([
@@ -37,7 +37,7 @@ const textlink: LinkParser.TextLinkParser = lazy(() =>
37
37
  return parse(content, params, rest, context);
38
38
  }))));
39
39
 
40
- const medialink: LinkParser.MediaLinkParser = lazy(() =>
40
+ export const medialink: LinkParser.MediaLinkParser = lazy(() =>
41
41
  constraint(State.link | State.media, false,
42
42
  syntax(Syntax.link, 2, 10, State.linkers,
43
43
  bind(reverse(sequence([
@@ -50,6 +50,11 @@ const medialink: LinkParser.MediaLinkParser = lazy(() =>
50
50
  ([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) =>
51
51
  parse(content, params, rest, context)))));
52
52
 
53
+ export const linemedialink: LinkParser.LineMediaLinkParser = surround(
54
+ linebreak,
55
+ union([medialink]),
56
+ /^(?=[^\S\n]*(?:$|\n))/);
57
+
53
58
  export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
54
59
  creation(10, precedence(2,
55
60
  bind(reverse(tails([
@@ -3,7 +3,7 @@ import { union, inits, tails, some, syntax, creation, precedence, constraint, va
3
3
  import { unsafelink, uri, option as linkoption, resolve } from './link';
4
4
  import { attributes } from './html';
5
5
  import { unsafehtmlentity } from './htmlentity';
6
- import { txt, str } from '../source';
6
+ import { txt, linebreak, str } from '../source';
7
7
  import { Syntax, State } from '../context';
8
8
  import { ReadonlyURL } from 'spica/url';
9
9
  import { unshift, push } from 'spica/array';
@@ -61,6 +61,11 @@ export const media: MediaParser = lazy(() => validate(['![', '!{'], open(
61
61
  ({ source: `{ ${INSECURE_URI}${params.join('')} }${rest}`, context });
62
62
  }))))));
63
63
 
64
+ export const linemedia: MediaParser.LineMediaParser = surround(
65
+ linebreak,
66
+ union([media]),
67
+ /^(?=[^\S\n]*(?:$|\n))/);
68
+
64
69
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(union([
65
70
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
66
71
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
@@ -1,12 +1,21 @@
1
- import { ShortmediaParser } from '../inline';
2
- import { union, constraint, rewrite, open, convert } from '../../combinator';
1
+ import { ShortMediaParser } from '../inline';
2
+ import { union, constraint, focus, rewrite, open, convert } from '../../combinator';
3
3
  import { url } from './autolink/url';
4
4
  import { media } from './media';
5
+ import { linebreak } from '../source';
5
6
  import { State } from '../context';
6
7
 
7
- export const shortmedia: ShortmediaParser = rewrite(
8
+ export const shortmedia: ShortMediaParser = rewrite(
8
9
  constraint(State.media, false,
9
10
  open('!', url)),
10
11
  convert(
11
12
  source => `!{ ${source.slice(1)} }`,
12
13
  union([media])));
14
+
15
+ export const lineshortmedia: ShortMediaParser.LineShortMediaParser = open(
16
+ linebreak,
17
+ focus(
18
+ /^!https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
19
+ convert(
20
+ source => `!{ ${source.slice(1)} }`,
21
+ union([media]))));
@@ -56,11 +56,11 @@ describe('Unit: parser/inline', () => {
56
56
  assert.deepStrictEqual(inspect(parser('{}')), [['{', '}'], '']);
57
57
  assert.deepStrictEqual(inspect(parser('{a}')), [['<a class="url" href="a">a</a>'], '']);
58
58
  assert.deepStrictEqual(inspect(parser('{{a}}')), [['<span class="template">{{a}}</span>'], '']);
59
- assert.deepStrictEqual(inspect(parser('!{}')), [['!', '{', '}'], '']);
60
- assert.deepStrictEqual(inspect(parser('!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
61
- assert.deepStrictEqual(inspect(parser('!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
62
- assert.deepStrictEqual(inspect(parser('!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
63
- assert.deepStrictEqual(inspect(parser('!!{a}')), [['!', '<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
59
+ assert.deepStrictEqual(inspect(parser('\r!{}')), [['!', '{', '}'], '']);
60
+ assert.deepStrictEqual(inspect(parser('\r!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
61
+ assert.deepStrictEqual(inspect(parser('\r!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
62
+ assert.deepStrictEqual(inspect(parser('\r!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
63
+ assert.deepStrictEqual(inspect(parser('\r!!{a}')), [['!', '!', '<a class="url" href="a">a</a>'], '']);
64
64
  assert.deepStrictEqual(inspect(parser('${a}')), [['$', '<a class="url" href="a">a</a>'], '']);
65
65
  assert.deepStrictEqual(inspect(parser('${{a}}')), [['$', '<span class="template">{{a}}</span>'], '']);
66
66
  assert.deepStrictEqual(inspect(parser('${{{a}}}')), [['$', '<span class="template">{{{a}}}</span>'], '']);
@@ -105,11 +105,8 @@ describe('Unit: parser/inline', () => {
105
105
  assert.deepStrictEqual(inspect(parser('0http://host')), [['0http', ':', '/', '/', 'host'], '']);
106
106
  assert.deepStrictEqual(inspect(parser('0aAhttp://host')), [['0aAhttp', ':', '/', '/', 'host'], '']);
107
107
  assert.deepStrictEqual(inspect(parser('?http://host')), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
108
- assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
108
+ assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
109
109
  assert.deepStrictEqual(inspect(parser('0?http://host')), [['0', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
110
- assert.deepStrictEqual(inspect(parser('0!!http://host')), [['0', '!', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
111
- assert.deepStrictEqual(inspect(parser('0?!http://host')), [['0', '?', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
112
- assert.deepStrictEqual(inspect(parser('0!?http://host')), [['0', '!', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
113
110
  assert.deepStrictEqual(inspect(parser('_http://host')), [['_', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
114
111
  assert.deepStrictEqual(inspect(parser('_http://host_')), [['<em><a class="url" href="http://host" target="_blank">http://host</a></em>'], '']);
115
112
  assert.deepStrictEqual(inspect(parser('*http://host*')), [['<strong><a class="url" href="http://host" target="_blank">http://host</a></strong>'], '']);
@@ -7,7 +7,7 @@ import { comment } from './inline/comment';
7
7
  import { math } from './inline/math';
8
8
  import { extension } from './inline/extension';
9
9
  import { ruby } from './inline/ruby';
10
- import { link } from './inline/link';
10
+ import { textlink, linemedialink } from './inline/link';
11
11
  import { html } from './inline/html';
12
12
  import { insertion } from './inline/insertion';
13
13
  import { deletion } from './inline/deletion';
@@ -15,9 +15,9 @@ import { mark } from './inline/mark';
15
15
  import { emphasis } from './inline/emphasis';
16
16
  import { strong } from './inline/strong';
17
17
  import { code } from './inline/code';
18
- import { media } from './inline/media';
18
+ import { linemedia } from './inline/media';
19
19
  import { htmlentity } from './inline/htmlentity';
20
- import { shortmedia } from './inline/shortmedia';
20
+ import { lineshortmedia } from './inline/shortmedia';
21
21
  import { autolink } from './inline/autolink';
22
22
  import { bracket } from './inline/bracket';
23
23
  import { text } from './source';
@@ -41,7 +41,7 @@ export import CodeParser = InlineParser.CodeParser;
41
41
  export import MediaParser = InlineParser.MediaParser;
42
42
  export import HTMLEntityParser = InlineParser.HTMLEntityParser;
43
43
  export import UnsafeHTMLEntityParser = InlineParser.UnsafeHTMLEntityParser;
44
- export import ShortmediaParser = InlineParser.ShortmediaParser;
44
+ export import ShortMediaParser = InlineParser.ShortMediaParser;
45
45
  export import AutolinkParser = InlineParser.AutolinkParser;
46
46
  export import BracketParser = InlineParser.BracketParser;
47
47
 
@@ -53,8 +53,9 @@ export const inline: InlineParser = union([
53
53
  math,
54
54
  extension,
55
55
  ruby,
56
- link,
57
- media,
56
+ textlink,
57
+ linemedialink,
58
+ linemedia,
58
59
  html,
59
60
  insertion,
60
61
  deletion,
@@ -63,7 +64,7 @@ export const inline: InlineParser = union([
63
64
  emphasis,
64
65
  code,
65
66
  htmlentity,
66
- shortmedia,
67
+ lineshortmedia,
67
68
  autolink,
68
69
  bracket,
69
70
  text
@@ -37,7 +37,7 @@ describe('Unit: parser/processor/footnote', () => {
37
37
  footnote.outerHTML,
38
38
  html('ol', [
39
39
  html('li', { id: 'annotation::def:1' }, [
40
- 'a b',
40
+ html('span', { id: 'note::a_b' }, 'a b'),
41
41
  html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
42
42
  ]),
43
43
  ]).outerHTML);
@@ -67,11 +67,11 @@ describe('Unit: parser/processor/footnote', () => {
67
67
  footnote.outerHTML,
68
68
  html('ol', [
69
69
  html('li', { id: 'annotation::def:1' }, [
70
- '1',
70
+ html('span', { id: 'note::1' }, '1'),
71
71
  html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
72
72
  ]),
73
73
  html('li', { id: 'annotation::def:2' }, [
74
- '12345678901234567890',
74
+ html('span', { id: 'note::12345678901234567890' }, '12345678901234567890'),
75
75
  html('sup', [html('a', { href: '#annotation::ref:2' }, '^2')])
76
76
  ]),
77
77
  ]).outerHTML);
@@ -113,22 +113,22 @@ describe('Unit: parser/processor/footnote', () => {
113
113
  footnote.outerHTML,
114
114
  html('ol', [
115
115
  html('li', { id: 'annotation::def:1' }, [
116
- '1',
116
+ html('span', { id: 'note::1' }, '1'),
117
117
  html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
118
118
  ]),
119
119
  html('li', { id: 'annotation::def:2' }, [
120
- '2',
120
+ html('span', { id: 'note::2' }, '2'),
121
121
  html('sup', [
122
122
  html('a', { href: '#annotation::ref:2' }, '^2'),
123
123
  html('a', { href: '#annotation::ref:4' }, '^4'),
124
124
  ]),
125
125
  ]),
126
126
  html('li', { id: 'annotation::def:3' }, [
127
- '3',
127
+ html('span', { id: 'note::3' }, '3'),
128
128
  html('sup', [html('a', { href: '#annotation::ref:3' }, '^3')])
129
129
  ]),
130
130
  html('li', { id: 'annotation::def:4' }, [
131
- '4',
131
+ html('span', { id: 'note::4' }, '4'),
132
132
  html('sup', [html('a', { href: '#annotation::ref:5' }, '^5')])
133
133
  ]),
134
134
  ]).outerHTML);
@@ -151,13 +151,13 @@ describe('Unit: parser/processor/footnote', () => {
151
151
  assert.deepStrictEqual(
152
152
  [...target.children].map(el => el.outerHTML),
153
153
  [
154
- '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>',
155
- '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></aside>',
154
+ '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>',
155
+ '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></aside>',
156
156
  '<p><sup class="annotation" id="annotation::ref:1" title="a"><span hidden="">a</span><a href="#annotation::def:1">*1</a></sup></p>',
157
157
  ]);
158
158
  assert.deepStrictEqual(
159
159
  footnote.outerHTML,
160
- '<ol><li id="annotation::def:1">a<sup><a href="#annotation::ref:1">^1</a></sup></li></ol>');
160
+ '<ol><li id="annotation::def:1"><span id="note::a">a</span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>');
161
161
  }
162
162
  });
163
163
 
@@ -180,7 +180,7 @@ describe('Unit: parser/processor/footnote', () => {
180
180
  footnote.outerHTML,
181
181
  html('ol', [
182
182
  html('li', { id: 'annotation:0:def:1' }, [
183
- 'a b',
183
+ html('span', { id: 'note:0:a_b' }, 'a b'),
184
184
  html('sup', [html('a', { href: '#annotation:0:ref:1' }, '^1')])
185
185
  ]),
186
186
  ]).outerHTML);
@@ -202,7 +202,7 @@ describe('Unit: parser/processor/footnote', () => {
202
202
  ]).outerHTML,
203
203
  html('ol', { class: 'annotations' }, [
204
204
  html('li', { id: 'annotation::def:1', 'data-marker': '*1' }, [
205
- '1',
205
+ html('span', { id: 'note::1' }, '1'),
206
206
  html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
207
207
  ]),
208
208
  ]).outerHTML,
@@ -220,11 +220,11 @@ describe('Unit: parser/processor/footnote', () => {
220
220
  ]).outerHTML,
221
221
  html('ol', { class: 'annotations' }, [
222
222
  html('li', { id: 'annotation::def:2', 'data-marker': '*2' }, [
223
- '2',
223
+ html('span', { id: 'note::2' }, '2'),
224
224
  html('sup', [html('a', { href: '#annotation::ref:2' }, '^2')])
225
225
  ]),
226
226
  html('li', { id: 'annotation::def:3', 'data-marker': '*3' }, [
227
- '3',
227
+ html('span', { id: 'note::3' }, '3'),
228
228
  html('sup', [html('a', { href: '#annotation::ref:3' }, '^3')])
229
229
  ]),
230
230
  ]).outerHTML,
@@ -237,7 +237,7 @@ describe('Unit: parser/processor/footnote', () => {
237
237
  ]).outerHTML,
238
238
  html('ol', { class: 'annotations' }, [
239
239
  html('li', { id: 'annotation::def:4', 'data-marker': '*4' }, [
240
- '4',
240
+ html('span', { id: 'note::4' }, '4'),
241
241
  html('sup', [html('a', { href: '#annotation::ref:4' }, '^4')])
242
242
  ]),
243
243
  ]).outerHTML,
@@ -267,7 +267,7 @@ describe('Unit: parser/processor/footnote', () => {
267
267
  footnote.outerHTML,
268
268
  html('ol', [
269
269
  html('li', { id: 'reference::def:1' }, [
270
- 'a b',
270
+ html('span', { id: 'note::a_b' }, 'a b'),
271
271
  html('sup', [html('a', { href: '#reference::ref:1' }, '^1')])
272
272
  ]),
273
273
  ]).outerHTML);
@@ -301,7 +301,7 @@ describe('Unit: parser/processor/footnote', () => {
301
301
  footnote.outerHTML,
302
302
  html('ol', [
303
303
  html('li', { id: 'reference::def:1' }, [
304
- 'b',
304
+ html('span', { id: 'note::b' }, 'b'),
305
305
  html('sup', [
306
306
  html('a', { href: '#reference::ref:1' }, '^1'),
307
307
  html('a', { href: '#reference::ref:2', title: 'b' }, '^2'),