securemark 0.233.2 → 0.234.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.
@@ -1,14 +1,19 @@
1
1
  import { ReplyParser } from '../../block';
2
- import { tails, line, validate, creator, reverse, fmap } from '../../../combinator';
3
- import { anchor, syntax } from '../../inline/autolink/anchor';
2
+ import { union, tails, line, validate, focus, creator, reverse, fmap } from '../../../combinator';
3
+ import { anchor } from '../../inline/autolink/anchor';
4
4
  import { str } from '../../source';
5
5
  import { html, define, defrag } from 'typed-dom';
6
6
 
7
7
  export const cite: ReplyParser.CiteParser = creator(line(fmap(validate(
8
8
  '>>',
9
9
  reverse(tails([
10
- str(/^>*(?=>>)/),
11
- validate(new RegExp(`${syntax.source}[^\S\n]*(?:$|\n)`), anchor),
10
+ str(/^>*(?=>>[^>\s]+[^\S\n]*(?:$|\n))/),
11
+ union([
12
+ anchor,
13
+ // Subject page representation.
14
+ // リンクの実装は後で検討
15
+ focus(/^>>\.[^\S\n]*(?:$|\n)/, () => [[html('a', { class: 'anchor' }, '>>.')], '']),
16
+ ]),
12
17
  ]))),
13
18
  ([el, quotes = '']: [HTMLElement, string?]) => [
14
19
  html('span', { class: 'cite' }, defrag([
@@ -47,8 +47,8 @@ describe('Unit: parser/block/reply/quote', () => {
47
47
  assert.deepStrictEqual(inspect(parser('> 0\n>> 1')), [['<span class="quote">&gt; 0<br>&gt;&gt; 1</span>', '<br>'], '']);
48
48
  assert.deepStrictEqual(inspect(parser('>> 0\n> 1')), [['<span class="quote">&gt;&gt; 0<br>&gt; 1</span>', '<br>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('> \\')), [['<span class="quote">&gt; \\</span>', '<br>'], '']);
50
- assert.deepStrictEqual(inspect(parser('> >>0\n> > b')), [['<span class="quote">&gt; <a href="?comment=0" class="anchor">&gt;&gt;0</a><br>&gt; &gt; b</span>', '<br>'], '']);
51
- assert.deepStrictEqual(inspect(parser('> >>0\n> > b\n> c')), [['<span class="quote">&gt; <a href="?comment=0" class="anchor">&gt;&gt;0</a><br>&gt; &gt; b<br>&gt; c</span>', '<br>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('> >>0\n> > b')), [['<span class="quote">&gt; <a href="?at=0" class="anchor">&gt;&gt;0</a><br>&gt; &gt; b</span>', '<br>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('> >>0\n> > b\n> c')), [['<span class="quote">&gt; <a href="?at=0" class="anchor">&gt;&gt;0</a><br>&gt; &gt; b<br>&gt; c</span>', '<br>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser('> > a\n> > b\n> > c')), [['<span class="quote">&gt; &gt; a<br>&gt; &gt; b<br>&gt; &gt; c</span>', '<br>'], '']);
53
53
  assert.deepStrictEqual(inspect(parser('> > > a\n> > > b')), [['<span class="quote">&gt; &gt; &gt; a<br>&gt; &gt; &gt; b</span>', '<br>'], '']);
54
54
  assert.deepStrictEqual(inspect(parser('> #a')), [['<span class="quote">&gt; <a href="/hashtags/a" class="hashtag">#a</a></span>', '<br>'], '']);
@@ -7,14 +7,14 @@ describe('Unit: parser/block/reply', () => {
7
7
  const parser = (source: string) => some(reply)(source, {});
8
8
 
9
9
  it('basic', () => {
10
- assert.deepStrictEqual(inspect(parser('>>1')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span></p>'], '']);
11
- assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a</p>'], '']);
12
- assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a<br><a href="?comment=2" class="anchor">&gt;&gt;2</a></p>'], '']);
13
- assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
14
- assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span></p>'], '']);
15
- assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br>b</p>'], '']);
16
- assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
17
- assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a<br>&gt;&gt; b</span></p>'], '']);
10
+ assert.deepStrictEqual(inspect(parser('>>1')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span></p>'], '']);
11
+ assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br>a</p>'], '']);
12
+ assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br>a<br><a href="?at=2" class="anchor">&gt;&gt;2</a></p>'], '']);
13
+ assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="cite">&gt;<a href="?at=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
14
+ assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span></p>'], '']);
15
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br>b</p>'], '']);
16
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br><span class="cite">&gt;<a href="?at=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
17
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">&gt;<a href="?at=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a<br>&gt;&gt; b</span></p>'], '']);
18
18
  });
19
19
 
20
20
  });
@@ -9,6 +9,13 @@ import { visualize } from '../util';
9
9
  import { html, defrag } from 'typed-dom';
10
10
  import { push, pop } from 'spica/array';
11
11
 
12
+ /*
13
+ 必ず対象指定から始まる
14
+ 対象がページである場合>>.を表現方法とする
15
+ 対象をURLで指定すべき(引用ツリーにルートを追加する)場合はない
16
+ 対象と引用は1:N(分割)、N:1(統合)のみ可能、N:N(混合)は不可能
17
+ */
18
+
12
19
  export const reply: ReplyParser = block(validate('>', localize(fmap(
13
20
  inits([
14
21
  some(inits([
@@ -17,10 +24,9 @@ export const reply: ReplyParser = block(validate('>', localize(fmap(
17
24
  ])),
18
25
  some(subsequence([
19
26
  some(quote),
20
- fmap(
21
- rewrite(
22
- some(anyline, delimiter),
23
- trim(visualize(some(inline)))),
27
+ fmap(rewrite(
28
+ some(anyline, delimiter),
29
+ trim(visualize(some(inline)))),
24
30
  ns => push(ns, [html('br')])),
25
31
  ])),
26
32
  ]),
@@ -10,8 +10,6 @@ describe('Unit: parser/inline/autolink/anchor', () => {
10
10
  assert.deepStrictEqual(inspect(parser('')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('>')), undefined);
12
12
  assert.deepStrictEqual(inspect(parser('>>')), undefined);
13
- assert.deepStrictEqual(inspect(parser('>>0A')), undefined);
14
- assert.deepStrictEqual(inspect(parser('>>A')), undefined);
15
13
  assert.deepStrictEqual(inspect(parser('>>-0')), undefined);
16
14
  assert.deepStrictEqual(inspect(parser('>>01#')), undefined);
17
15
  assert.deepStrictEqual(inspect(parser('>>01@')), undefined);
@@ -22,12 +20,15 @@ describe('Unit: parser/inline/autolink/anchor', () => {
22
20
  });
23
21
 
24
22
  it('valid', () => {
25
- assert.deepStrictEqual(inspect(parser('>>0')), [['<a href="?comment=0" class="anchor">&gt;&gt;0</a>'], '']);
26
- assert.deepStrictEqual(inspect(parser('>>a')), [['<a href="?comment=a" class="anchor">&gt;&gt;a</a>'], '']);
27
- assert.deepStrictEqual(inspect(parser('>>0-')), [['<a href="?comment=0" class="anchor">&gt;&gt;0</a>'], '-']);
28
- assert.deepStrictEqual(inspect(parser('>>0-a')), [['<a href="?comment=0-a" class="anchor">&gt;&gt;0-a</a>'], '']);
29
- assert.deepStrictEqual(inspect(parser('>>0-A')), [['<a href="?comment=0" class="anchor">&gt;&gt;0</a>'], '-A']);
30
- assert.deepStrictEqual(inspect(parser('>>0--a')), [['<a href="?comment=0" class="anchor">&gt;&gt;0</a>'], '--a']);
23
+ assert.deepStrictEqual(inspect(parser('>>0')), [['<a href="?at=0" class="anchor">&gt;&gt;0</a>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('>>a')), [['<a href="?at=a" class="anchor">&gt;&gt;a</a>'], '']);
25
+ assert.deepStrictEqual(inspect(parser('>>A')), [['<a href="?at=A" class="anchor">&gt;&gt;A</a>'], '']);
26
+ assert.deepStrictEqual(inspect(parser('>>0-')), [['<a href="?at=0" class="anchor">&gt;&gt;0</a>'], '-']);
27
+ assert.deepStrictEqual(inspect(parser('>>0-a')), [['<a href="?at=0-a" class="anchor">&gt;&gt;0-a</a>'], '']);
28
+ assert.deepStrictEqual(inspect(parser('>>0-A')), [['<a href="?at=0-A" class="anchor">&gt;&gt;0-A</a>'], '']);
29
+ assert.deepStrictEqual(inspect(parser('>>0--a')), [['<a href="?at=0" class="anchor">&gt;&gt;0</a>'], '--a']);
30
+ assert.deepStrictEqual(inspect(parser('>>2000-01-31-23-59-59-999-JST')), [['<a href="?at=2000-01-31-23-59-59-999-JST" class="anchor">&gt;&gt;2000-01-31-23-59-59-999-JST</a>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('>>A/2000-01-31-23-59-59-JST')), [['<a href="/@A/timeline/2000-01-31-23-59-59-JST" class="anchor">&gt;&gt;A/2000-01-31-23-59-59-JST</a>'], '']);
31
32
  });
32
33
 
33
34
  });
@@ -1,18 +1,29 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { union, validate, rewrite, context, convert, fmap, lazy } from '../../../combinator';
2
+ import { union, validate, focus, context, convert, fmap, lazy } from '../../../combinator';
3
3
  import { link } from '../link';
4
- import { str } from '../../source';
5
4
  import { define } from 'typed-dom';
6
5
 
7
- export const syntax = /^>>[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:])/;
6
+ // Timeline(pseudonym): user/tid
7
+ // Thread(anonymous): cid
8
8
 
9
- export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>', fmap(rewrite(
10
- str(syntax),
9
+ // tid: YYYY-MM-DD-HH-MM-SS-TMZ
10
+ // cid: YYYY-MM-DD-HH-MM-SS-mmm-TMZ
11
+
12
+ // 内部表現はUnixTimeに統一する(時系列順)
13
+ // 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
14
+
15
+ export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>', fmap(focus(
16
+ /^>>(?:[A-Za-z][0-9A-Za-z]*(?:-[0-9A-Za-z]+)*\/)?[0-9A-Za-z]+(?:-[0-9A-Za-z]+)*(?![0-9A-Za-z@#:])/,
11
17
  context({ syntax: { inline: {
12
18
  link: true,
13
19
  autolink: false,
14
20
  }}},
15
21
  convert(
16
- source => `[${source}]{ ?comment=${source.slice(2)} }`,
22
+ source =>
23
+ `[${source}]{ ${
24
+ source.includes('/')
25
+ ? `/@${source.slice(2).replace('/', '/timeline/')}`
26
+ : `?at=${source.slice(2)}`
27
+ } }`,
17
28
  union([link])))),
18
29
  ([el]) => [define(el, { class: 'anchor' })])));
@@ -13,50 +13,49 @@ describe('Unit: parser/inline/comment', () => {
13
13
  assert.deepStrictEqual(inspect(parser('[#[#')), undefined);
14
14
  assert.deepStrictEqual(inspect(parser('[#a#]')), undefined);
15
15
  assert.deepStrictEqual(inspect(parser('[#a b#]')), undefined);
16
- assert.deepStrictEqual(inspect(parser('[# ')), [['[', '#', ' '], '']);
17
- assert.deepStrictEqual(inspect(parser('[# \n a')), [['[', '#', '<br>', ' ', 'a'], '']);
16
+ assert.deepStrictEqual(inspect(parser('[# ')), [['[#'], '']);
17
+ assert.deepStrictEqual(inspect(parser('[# \n a')), [['[#', '<br>', ' ', 'a'], '']);
18
18
  assert.deepStrictEqual(inspect(parser('[##]')), undefined);
19
- assert.deepStrictEqual(inspect(parser('[# #]')), undefined);
20
- assert.deepStrictEqual(inspect(parser('[# #] #]')), undefined);
21
- assert.deepStrictEqual(inspect(parser('[# [#')), [['[', '#', ' ', '[', '#'], '']);
22
- assert.deepStrictEqual(inspect(parser('[# [# ')), [['[', '#', ' ', '[', '#', ' '], '']);
23
- assert.deepStrictEqual(inspect(parser('[# [# a')), [['[', '#', ' ', '[', '#', ' ', 'a'], '']);
24
- assert.deepStrictEqual(inspect(parser('[# [# a #]')), [['[', '#', ' ', '<span class="comment">[# a #]</span>'], '']);
25
- assert.deepStrictEqual(inspect(parser('[# a[#')), [['[', '#', ' ', 'a', '[', '#'], '']);
26
- assert.deepStrictEqual(inspect(parser('[# a [#')), [['[', '#', ' ', 'a', ' ', '[', '#'], '']);
27
- assert.deepStrictEqual(inspect(parser('[# a [# ')), [['[', '#', ' ', 'a', ' ', '[', '#', ' '], '']);
28
- assert.deepStrictEqual(inspect(parser('[# a [# b')), [['[', '#', ' ', 'a', ' ', '[', '#', ' ', 'b'], '']);
29
- assert.deepStrictEqual(inspect(parser('[# a [## b')), [['[', '#', ' ', 'a', ' ', '[', '#', '#', ' ', 'b'], '']);
30
- assert.deepStrictEqual(inspect(parser('[## a [# b')), [['[', '#', '#', ' ', 'a', ' ', '[', '#', ' ', 'b'], '']);
19
+ assert.deepStrictEqual(inspect(parser('[# [#')), [['[#', ' ', '[', '#'], '']);
20
+ assert.deepStrictEqual(inspect(parser('[# [# ')), [['[#', ' ', '[#'], '']);
21
+ assert.deepStrictEqual(inspect(parser('[# [# a')), [['[#', ' ', '[#', ' ', 'a'], '']);
22
+ assert.deepStrictEqual(inspect(parser('[# [# a #]')), [['[#', ' ', '<span class="comment"><input type="checkbox"><span>[# a #]</span></span>'], '']);
23
+ assert.deepStrictEqual(inspect(parser('[# a[#')), [['[#', ' ', 'a', '[', '#'], '']);
24
+ assert.deepStrictEqual(inspect(parser('[# a [#')), [['[#', ' ', 'a', ' ', '[', '#'], '']);
25
+ assert.deepStrictEqual(inspect(parser('[# a [# ')), [['[#', ' ', 'a', ' ', '[#'], '']);
26
+ assert.deepStrictEqual(inspect(parser('[# a [# b')), [['[#', ' ', 'a', ' ', '[#', ' ', 'b'], '']);
27
+ assert.deepStrictEqual(inspect(parser('[# a [## b')), [['[#', ' ', 'a', ' ', '[##', ' ', 'b'], '']);
28
+ assert.deepStrictEqual(inspect(parser('[## a [# b')), [['[##', ' ', 'a', ' ', '[#', ' ', 'b'], '']);
31
29
  assert.deepStrictEqual(inspect(parser('[#\\ a #]')), undefined);
32
- assert.deepStrictEqual(inspect(parser('[# a\\ #]')), [['[', '#', ' ', 'a', ' ', '#', ']'], '']);
33
- assert.deepStrictEqual(inspect(parser('[# a#]')), [['[', '#', ' ', 'a#', ']'], '']);
34
- assert.deepStrictEqual(inspect(parser('[# a ##]')), [['[', '#', ' ', 'a', ' ', '##', ']'], '']);
35
- assert.deepStrictEqual(inspect(parser('[# [## #]')), [['[', '#', ' ', '[', '#', '#', ' ', '#', ']'], '']);
36
- assert.deepStrictEqual(inspect(parser('[## [# ##]')), [['[', '#', '#', ' ', '[', '#', ' ', '##', ']'], '']);
37
- assert.deepStrictEqual(inspect(parser('[## a #]')), [['[', '#', '#', ' ', 'a', ' ', '#', ']'], '']);
30
+ assert.deepStrictEqual(inspect(parser('[# a\\ #]')), [['[#', ' ', 'a', ' ', '#', ']'], '']);
31
+ assert.deepStrictEqual(inspect(parser('[# a#]')), [['[#', ' ', 'a#', ']'], '']);
32
+ assert.deepStrictEqual(inspect(parser('[# a ##]')), [['[#', ' ', 'a', ' ', '##', ']'], '']);
33
+ assert.deepStrictEqual(inspect(parser('[# [## #]')), [['[#', ' ', '[##', ' ', '#', ']'], '']);
34
+ assert.deepStrictEqual(inspect(parser('[## [# ##]')), [['[##', ' ', '[#', ' ', '##', ']'], '']);
35
+ assert.deepStrictEqual(inspect(parser('[## a #]')), [['[##', ' ', 'a', ' ', '#', ']'], '']);
38
36
  assert.deepStrictEqual(inspect(parser(' [# a #]')), undefined);
39
37
  });
40
38
 
41
39
  it('basic', () => {
42
- assert.deepStrictEqual(inspect(parser('[# #]')), [['<span class="comment">[# #]</span>'], '']);
43
- assert.deepStrictEqual(inspect(parser('[# #]')), [['<span class="comment">[# #]</span>'], '']);
44
- assert.deepStrictEqual(inspect(parser('[# a #]')), [['<span class="comment">[# a #]</span>'], '']);
45
- assert.deepStrictEqual(inspect(parser('[# a b #]')), [['<span class="comment">[# a b #]</span>'], '']);
46
- assert.deepStrictEqual(inspect(parser('[# a\nb #]')), [['<span class="comment">[# a<br>b #]</span>'], '']);
47
- assert.deepStrictEqual(inspect(parser('[# a #] #]')), [['<span class="comment">[# a #]</span>'], ' #]']);
48
- assert.deepStrictEqual(inspect(parser('[# ##] #]')), [['<span class="comment">[# ##] #]</span>'], '']);
49
- assert.deepStrictEqual(inspect(parser('[# [# a #] #]')), [['<span class="comment">[# <span class="comment">[# a #]</span> #]</span>'], '']);
50
- assert.deepStrictEqual(inspect(parser('[# [## a ##] #]')), [['<span class="comment">[# <span class="comment">[## a ##]</span> #]</span>'], '']);
51
- assert.deepStrictEqual(inspect(parser('[## a ##]')), [['<span class="comment">[## a ##]</span>'], '']);
52
- assert.deepStrictEqual(inspect(parser('[## #] ##]')), [['<span class="comment">[## #] ##]</span>'], '']);
53
- assert.deepStrictEqual(inspect(parser('[## [# a #] ##]')), [['<span class="comment">[## <span class="comment">[# a #]</span> ##]</span>'], '']);
54
- assert.deepStrictEqual(inspect(parser('[# a #]b')), [['<span class="comment">[# a #]</span>'], 'b']);
55
- assert.deepStrictEqual(inspect(parser('[#\na\n#]')), [['<span class="comment">[# a #]</span>'], '']);
56
- assert.deepStrictEqual(inspect(parser('[# &a; #]')), [['<span class="comment">[# <span class="invalid">&amp;a;</span> #]</span>'], '']);
57
- assert.deepStrictEqual(inspect(parser('[# &copy; #]')), [['<span class="comment">[# © #]</span>'], '']);
58
- assert.deepStrictEqual(inspect(parser('[# &amp;copy; #]')), [['<span class="comment">[# &amp;copy; #]</span>'], '']);
59
- assert.deepStrictEqual(inspect(parser('[# \\ a #]')), [['<span class="comment">[# a #]</span>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('[# #]')), [['<span class="comment"><input type="checkbox"><span>[# #]</span></span>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('[# #]')), [['<span class="comment"><input type="checkbox"><span>[# #]</span></span>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('[# #]')), [['<span class="comment"><input type="checkbox"><span>[# #]</span></span>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('[# a #]')), [['<span class="comment"><input type="checkbox"><span>[# a #]</span></span>'], '']);
44
+ assert.deepStrictEqual(inspect(parser('[# a b #]')), [['<span class="comment"><input type="checkbox"><span>[# a b #]</span></span>'], '']);
45
+ assert.deepStrictEqual(inspect(parser('[# a\nb #]')), [['<span class="comment"><input type="checkbox"><span>[# a<br>b #]</span></span>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('[# a #] #]')), [['<span class="comment"><input type="checkbox"><span>[# a #]</span></span>'], ' #]']);
47
+ assert.deepStrictEqual(inspect(parser('[# ##] #]')), [['<span class="comment"><input type="checkbox"><span>[# ##] #]</span></span>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('[# [# a #] #]')), [['<span class="comment"><input type="checkbox"><span>[# <span class="comment"><input type="checkbox"><span>[# a #]</span></span> #]</span></span>'], '']);
49
+ assert.deepStrictEqual(inspect(parser('[# [## a ##] #]')), [['<span class="comment"><input type="checkbox"><span>[# <span class="comment"><input type="checkbox"><span>[## a ##]</span></span> #]</span></span>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('[## a ##]')), [['<span class="comment"><input type="checkbox"><span>[## a ##]</span></span>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('[## #] ##]')), [['<span class="comment"><input type="checkbox"><span>[## #] ##]</span></span>'], '']);
52
+ assert.deepStrictEqual(inspect(parser('[## [# a #] ##]')), [['<span class="comment"><input type="checkbox"><span>[## <span class="comment"><input type="checkbox"><span>[# a #]</span></span> ##]</span></span>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('[# a #]b')), [['<span class="comment"><input type="checkbox"><span>[# a #]</span></span>'], 'b']);
54
+ assert.deepStrictEqual(inspect(parser('[#\na\n#]')), [['<span class="comment"><input type="checkbox"><span>[#<br>a<br>#]</span></span>'], '']);
55
+ assert.deepStrictEqual(inspect(parser('[# &a; #]')), [['<span class="comment"><input type="checkbox"><span>[# <span class="invalid">&amp;a;</span> #]</span></span>'], '']);
56
+ assert.deepStrictEqual(inspect(parser('[# &copy; #]')), [['<span class="comment"><input type="checkbox"><span>[# © #]</span></span>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('[# &amp;copy; #]')), [['<span class="comment"><input type="checkbox"><span>[# &amp;copy; #]</span></span>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('[# \\ a #]')), [['<span class="comment"><input type="checkbox"><span>[# a #]</span></span>'], '']);
60
59
  });
61
60
 
62
61
  });
@@ -1,24 +1,24 @@
1
1
  import { CommentParser } from '../inline';
2
- import { eval } from '../../combinator/data/parser';
3
- import { union, some, validate, creator, surround, match, lazy } from '../../combinator';
2
+ import { union, some, validate, creator, surround, open, close, match, lazy } from '../../combinator';
4
3
  import { inline } from '../inline';
5
4
  import { text, str } from '../source';
6
5
  import { html, defrag } from 'typed-dom';
7
6
  import { memoize } from 'spica/memoize';
8
- import { unshift, push, pop } from 'spica/array';
7
+ import { unshift, push } from 'spica/array';
9
8
 
10
9
  export const comment: CommentParser = lazy(() => creator(validate('[#', match(
11
10
  /^(?=\[(#+)\s)/,
12
11
  memoize(
13
- ([, fence], closer = new RegExp(String.raw`^\s+${fence}\]`)) =>
12
+ ([, fence]) =>
14
13
  surround(
15
- str(/^\[(\S+)\s+(?!\1\])/),
16
- union([some(inline, closer)]),
17
- str(closer), true,
18
- ([, bs = []], rest) => [[
19
- html('span',
20
- { class: 'comment' },
21
- defrag(push(unshift([`[${fence} `], bs), [` ${fence}]`]))),
14
+ open(str(`[${fence}`), some(text, new RegExp(String.raw`^\s+${fence}\]|^\S`)), true),
15
+ union([some(inline, new RegExp(String.raw`^\s+${fence}\]`))]),
16
+ close(some(text, /^\S/), str(`${fence}]`)), true,
17
+ ([as, bs = [], cs], rest) => [[
18
+ html('span', { class: 'comment' }, [
19
+ html('input', { type: 'checkbox' }),
20
+ html('span', defrag(push(unshift(as, bs), cs))),
21
+ ]),
22
22
  ], rest],
23
- ([as, bs = []], rest, context) => [unshift(pop(eval(some(text)(`${as[0]}!`, context))!)[0], bs), rest]),
23
+ ([as, bs = []], rest) => [unshift(as, bs), rest]),
24
24
  ([, fence]) => fence)))));
@@ -9,8 +9,8 @@ describe('Unit: parser/inline/emphasis', () => {
9
9
  it('invalid', () => {
10
10
  assert.deepStrictEqual(inspect(parser('*')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('*a')), [['*', 'a'], '']);
12
- assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a', ' '], '*']);
13
- assert.deepStrictEqual(inspect(parser('*a\n*')), [['*', 'a', '<br>'], '*']);
12
+ assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a', ' ', '*'], '']);
13
+ assert.deepStrictEqual(inspect(parser('*a\n*')), [['*', 'a', '<br>', '*'], '']);
14
14
  assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a', ' '], '*']);
15
15
  assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a', '<span class="linebreak"> </span>'], '*']);
16
16
  assert.deepStrictEqual(inspect(parser('*a**b')), [['*', 'a', '**', 'b'], '']);
@@ -39,6 +39,8 @@ describe('Unit: parser/inline/emphasis', () => {
39
39
  it('nest', () => {
40
40
  assert.deepStrictEqual(inspect(parser('*a**b**c*')), [['<em>a<strong>b</strong>c</em>'], '']);
41
41
  assert.deepStrictEqual(inspect(parser('*a**b**c*d')), [['<em>a<strong>b</strong>c</em>'], 'd']);
42
+ assert.deepStrictEqual(inspect(parser('*a *b**')), [['<em>a <em>b</em></em>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('*a **b***')), [['<em>a <strong>b</strong></em>'], '']);
42
44
  assert.deepStrictEqual(inspect(parser('*`a`*')), [['<em><code data-src="`a`">a</code></em>'], '']);
43
45
  assert.deepStrictEqual(inspect(parser('*<small>*')), [['<em>&lt;small&gt;</em>'], '']);
44
46
  assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
@@ -1,5 +1,5 @@
1
1
  import { EmphasisParser } from '../inline';
2
- import { union, some, creator, surround, close, lazy } from '../../combinator';
2
+ import { union, sequence, some, creator, surround, close, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { strong } from './strong';
5
5
  import { str } from '../source';
@@ -9,7 +9,11 @@ import { unshift } from 'spica/array';
9
9
 
10
10
  export const emphasis: EmphasisParser = lazy(() => creator(surround(close(
11
11
  str('*'), /^(?!\*)/),
12
- startTight(some(union([strong, some(inline, '*')]))),
12
+ startTight(some(union([
13
+ strong,
14
+ some(inline, /^\s*\*/),
15
+ sequence([some(inline, '*'), inline]),
16
+ ]))),
13
17
  str('*'), false,
14
18
  ([as, bs, cs], rest) =>
15
19
  isEndTightNodes(bs)
@@ -1,29 +1,45 @@
1
- import { EmStrongParser } from '../inline';
2
- import { union, some, creator, surround, lazy, bind } from '../../combinator';
1
+ import { MarkdownParser } from '../../../markdown';
2
+ import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
3
+ import { Result, IntermediateParser } from '../../combinator/data/parser';
4
+ import { union, sequence, some, creator, surround, lazy, bind } from '../../combinator';
3
5
  import { inline } from '../inline';
6
+ import { strong } from './strong';
4
7
  import { str } from '../source';
5
8
  import { startTight, isEndTightNodes } from '../util';
6
9
  import { html, defrag } from 'typed-dom';
7
10
  import { unshift } from 'spica/array';
8
11
 
12
+ const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
13
+ some(inline, /^\s*\*\*/),
14
+ sequence([some(inline, '*'), inline]),
15
+ ])));
16
+ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
17
+ strong,
18
+ some(inline, /^\s*\*/),
19
+ sequence([some(inline, '*'), inline]),
20
+ ])));
21
+
9
22
  export const emstrong: EmStrongParser = lazy(() => creator(surround(
10
23
  str('***'),
11
- startTight(union([some(inline, '*')])),
24
+ startTight(some(union([
25
+ some(inline, /^\s*\*/),
26
+ sequence([some(inline, '*'), inline]),
27
+ ]))),
12
28
  str(/^\*{1,3}/), false,
13
- ([as, bs, cs], rest, context) => {
29
+ ([as, bs, cs], rest, context): Result<HTMLElement | string, MarkdownParser.Context> => {
14
30
  if (!isEndTightNodes(bs)) return [unshift(as, bs), cs[0] + rest];
15
31
  switch (cs[0]) {
16
32
  case '*':
17
- return bind<EmStrongParser>(
18
- union([some(inline, '**')]),
33
+ return bind<StrongParser>(
34
+ substrong,
19
35
  (ds, rest) =>
20
36
  rest.slice(0, 2) === '**' && isEndTightNodes(ds)
21
37
  ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
22
38
  : [unshift(['**', html('em', defrag(bs))], ds), rest])
23
39
  (rest, context) ?? [['**', html('em', defrag(bs))], rest];
24
40
  case '**':
25
- return bind<EmStrongParser>(
26
- union([some(inline, '*')]),
41
+ return bind<EmphasisParser>(
42
+ subemphasis,
27
43
  (ds, rest) =>
28
44
  rest.slice(0, 1) === '*' && isEndTightNodes(ds)
29
45
  ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds)))], rest.slice(1)]
@@ -38,7 +38,7 @@ describe('Unit: parser/inline/extension/index', () => {
38
38
  assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index:a_b">a b</a>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;]')), [['<a class="index" href="#index:a">a</a>'], '']);
40
40
  assert.deepStrictEqual(inspect(parser('[#a <wbr>]')), [['<a class="index" href="#index:a">a</a>'], '']);
41
- assert.deepStrictEqual(inspect(parser('[#a [# b #]]')), [['<a class="index" href="#index:a">a <span class="comment">[# b #]</span></a>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('[#a [# b #]]')), [['<a class="index" href="#index:a">a <span class="comment"><input type="checkbox"><span>[# b #]</span></span></a>'], '']);
42
42
  assert.deepStrictEqual(inspect(parser('[#a\\ ]')), [['<a class="index" href="#index:a">a</a>'], '']);
43
43
  assert.deepStrictEqual(inspect(parser('[#a\\ b]')), [['<a class="index" href="#index:a_b">a b</a>'], '']);
44
44
  assert.deepStrictEqual(inspect(parser('[#[]]')), [['<a class="index" href="#index:[]">[]</a>'], '']);
@@ -54,8 +54,8 @@ describe('Unit: parser/inline/extension/index', () => {
54
54
  assert.deepStrictEqual(inspect(parser('[#@a]')), [['<a class="index" href="#index:@a">@a</a>'], '']);
55
55
  assert.deepStrictEqual(inspect(parser('[#http://host]')), [['<a class="index" href="#index:http://host">http://host</a>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('[#!http://host]')), [['<a class="index" href="#index:!http://host">!http://host</a>'], '']);
57
- assert.deepStrictEqual(inspect(parser('[#[# #]]')), [['<a class="index"><span class="comment">[# #]</span></a>'], '']);
58
- assert.deepStrictEqual(inspect(parser('[#[# a #]]')), [['<a class="index"><span class="comment">[# a #]</span></a>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('[#[# #]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[# #]</span></span></a>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('[#[# a #]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[# a #]</span></span></a>'], '']);
59
59
  assert.deepStrictEqual(inspect(parser('[#a((b))]')), [['<a class="index" href="#index:a((b))">a<span class="paren">((b))</span></a>'], '']);
60
60
  assert.deepStrictEqual(inspect(parser('[#a[[b]]]')), [['<a class="index" href="#index:a[[b]]">a[[b]]</a>'], '']);
61
61
  });
@@ -83,7 +83,7 @@ describe('Unit: parser/inline/extension/index', () => {
83
83
  assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
84
84
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
85
85
  assert.deepStrictEqual(inspect(parser('[#a <wbr>|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
86
- assert.deepStrictEqual(inspect(parser('[#a [# b #]|#b]')), [['<a class="index" href="#index:b">a <span class="comment">[# b #]</span><span class="indexer" data-index="b"></span></a>'], '']);
86
+ assert.deepStrictEqual(inspect(parser('[#a [# b #]|#b]')), [['<a class="index" href="#index:b">a <span class="comment"><input type="checkbox"><span>[# b #]</span></span><span class="indexer" data-index="b"></span></a>'], '']);
87
87
  });
88
88
 
89
89
  });
@@ -45,13 +45,13 @@ describe('Unit: parser/inline/extension/placeholder', () => {
45
45
  assert.deepStrictEqual(inspect(parser('[^a\\ \\ ]')), [['<span class="invalid">a </span>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser('[^a<wbr>]')), [['<span class="invalid">a<wbr></span>'], '']);
47
47
  assert.deepStrictEqual(inspect(parser('[^a<wbr><wbr>]')), [['<span class="invalid">a<wbr><wbr></span>'], '']);
48
- assert.deepStrictEqual(inspect(parser('[^a[# b #]]')), [['<span class="invalid">a<span class="comment">[# b #]</span></span>'], '']);
49
- assert.deepStrictEqual(inspect(parser('[^a[# b #][# c #]]')), [['<span class="invalid">a<span class="comment">[# b #]</span><span class="comment">[# c #]</span></span>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('[^a[# b #]]')), [['<span class="invalid">a<span class="comment"><input type="checkbox"><span>[# b #]</span></span></span>'], '']);
49
+ 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>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser('[^\\]]')), [['<span class="invalid">]</span>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser('[^(])]')), [['<span class="invalid"><span class="paren">(])</span></span>'], '']);
52
52
  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>'], '']);
53
- assert.deepStrictEqual(inspect(parser('[^[# a #]]')), [['<span class="invalid"><span class="comment">[# a #]</span></span>'], '']);
54
- assert.deepStrictEqual(inspect(parser('[^[# a #]b]')), [['<span class="invalid"><span class="comment">[# a #]</span>b</span>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('[^[# a #]]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[# a #]</span></span></span>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('[^[# a #]b]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[# a #]</span></span>b</span>'], '']);
55
55
  });
56
56
 
57
57
  });
@@ -16,10 +16,10 @@ const optspec = {
16
16
  } as const;
17
17
  ObjectSetPrototypeOf(optspec, null);
18
18
 
19
- export const link: LinkParser = lazy(() => creator(10, bind(reverse(
19
+ export const link: LinkParser = lazy(() => creator(10, bind(
20
20
  validate(['[', '{'], '}', '\n',
21
21
  guard(context => context.syntax?.inline?.link ?? true,
22
- tails([
22
+ reverse(tails([
23
23
  context({ syntax: { inline: {
24
24
  link: false,
25
25
  }}},
@@ -12,8 +12,8 @@ describe('Unit: parser/inline/mark', () => {
12
12
  assert.deepStrictEqual(inspect(parser('==')), undefined);
13
13
  assert.deepStrictEqual(inspect(parser('==a')), [['==', 'a'], '']);
14
14
  assert.deepStrictEqual(inspect(parser('==a=')), [['==', 'a', '='], '']);
15
- assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' '], '==']);
16
- assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a', '<br>'], '==']);
15
+ assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' ', '=='], '']);
16
+ assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a', '<br>', '=='], '']);
17
17
  assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a', ' '], '==']);
18
18
  assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a', '<span class="linebreak"> </span>'], '==']);
19
19
  assert.deepStrictEqual(inspect(parser('== ==')), undefined);
@@ -36,6 +36,7 @@ describe('Unit: parser/inline/mark', () => {
36
36
 
37
37
  it('nest', () => {
38
38
  assert.deepStrictEqual(inspect(parser('==*==a==*==')), [['<mark><em><mark>a</mark></em></mark>'], '']);
39
+ assert.deepStrictEqual(inspect(parser('==a ==b====')), [['<mark>a <mark>b</mark></mark>'], '']);
39
40
  });
40
41
 
41
42
  });
@@ -1,5 +1,5 @@
1
1
  import { MarkParser } from '../inline';
2
- import { union, some, creator, surround, lazy } from '../../combinator';
2
+ import { union, sequence, some, creator, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
5
  import { startTight, isEndTightNodes } from '../util';
@@ -8,7 +8,10 @@ import { unshift } from 'spica/array';
8
8
 
9
9
  export const mark: MarkParser = lazy(() => creator(surround(
10
10
  str('=='),
11
- startTight(union([some(inline, '==')])),
11
+ startTight(some(union([
12
+ some(inline, /^\s*==/),
13
+ sequence([some(inline, '='), inline]),
14
+ ]))),
12
15
  str('=='), false,
13
16
  ([as, bs, cs], rest) =>
14
17
  isEndTightNodes(bs)
@@ -1,7 +1,6 @@
1
1
  import { MathParser } from '../inline';
2
- import { union, some, validate, verify, rewrite, creator, surround, lazy } from '../../combinator';
2
+ import { union, some, validate, rewrite, creator, surround, lazy } from '../../combinator';
3
3
  import { escsource, str } from '../source';
4
- import { isEndTightNodes } from '../util';
5
4
  import { html } from 'typed-dom';
6
5
 
7
6
  const disallowedCommand = /\\(?:begin|tiny|huge|large)(?![0-9a-z])/i;
@@ -10,15 +9,13 @@ export const math: MathParser = lazy(() => creator(validate('$', rewrite(
10
9
  union([
11
10
  surround(
12
11
  '$',
13
- verify(
14
- // Latex's reserved characters: # $ % ^ & _ { } ~ \
15
- // $[0-9]+ : Dollar
16
- // $[A-z]*- : Label
17
- // $[A-z]*(?!-) : Math
18
- // $[\^_[({|] : Math
19
- // $[#$%&] : Invalid first character in Latex syntax
20
- str(/^(?![\s{}#$%&]|\d+(?:[,.]\d+)*[^-+*/=<>^_~\\$]|-[\da-z]|[a-z]+-)(?:\\\$|[\x20-\x23\x25-\x7E])+/i),
21
- isEndTightNodes),
12
+ // Latex's reserved characters: # $ % ^ & _ { } ~ \
13
+ // $[0-9]+ : Dollar
14
+ // $[A-z]*- : Label
15
+ // $[A-z]*(?!-) : Math
16
+ // $[\^_[({|] : Math
17
+ // $[#$%&] : Invalid first character in Latex syntax
18
+ str(/^(?![\s{}#$%&]|\d+(?:[,.]\d+)*[^-+*/=<>^_~\\$]|-[\da-z]|[a-z]+-)(?:\\\$|\x20(?!\$)|[\x21-\x23\x25-\x7E])+/i),
22
19
  /^\$(?![0-9a-z])/i),
23
20
  surround('$', bracket, '$'),
24
21
  ]),
@@ -10,8 +10,8 @@ describe('Unit: parser/inline/strong', () => {
10
10
  assert.deepStrictEqual(inspect(parser('**')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('**a')), [['**', 'a'], '']);
12
12
  assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
13
- assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' '], '**']);
14
- assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a', '<br>'], '**']);
13
+ assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' ', '**'], '']);
14
+ assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a', '<br>', '**'], '']);
15
15
  assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' '], '**']);
16
16
  assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>'], '**']);
17
17
  assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
@@ -38,6 +38,7 @@ describe('Unit: parser/inline/strong', () => {
38
38
  assert.deepStrictEqual(inspect(parser('**a*b*c**')), [['<strong>a<em>b</em>c</strong>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser('**a*b*c**d')), [['<strong>a<em>b</em>c</strong>'], 'd']);
40
40
  assert.deepStrictEqual(inspect(parser('**a *b***')), [['<strong>a <em>b</em></strong>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('**a **b****')), [['<strong>a <strong>b</strong></strong>'], '']);
41
42
  assert.deepStrictEqual(inspect(parser('**`a`**')), [['<strong><code data-src="`a`">a</code></strong>'], '']);
42
43
  assert.deepStrictEqual(inspect(parser('**<small>**')), [['<strong>&lt;small&gt;</strong>'], '']);
43
44
  assert.deepStrictEqual(inspect(parser('**(*a*)**')), [['<strong><span class="paren">(<em>a</em>)</span></strong>'], '']);