securemark 0.248.1 → 0.250.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 (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/index.js +351 -284
  4. package/karma.conf.js +1 -1
  5. package/markdown.d.ts +11 -5
  6. package/package.json +12 -12
  7. package/src/parser/api/parse.test.ts +6 -6
  8. package/src/parser/block/blockquote.test.ts +2 -2
  9. package/src/parser/block/dlist.test.ts +2 -1
  10. package/src/parser/block/dlist.ts +4 -4
  11. package/src/parser/block/extension/figure.ts +3 -3
  12. package/src/parser/block/heading.test.ts +1 -0
  13. package/src/parser/block/heading.ts +4 -4
  14. package/src/parser/block/olist.ts +3 -2
  15. package/src/parser/block/paragraph.test.ts +10 -10
  16. package/src/parser/block/paragraph.ts +2 -2
  17. package/src/parser/block/reply.ts +2 -2
  18. package/src/parser/block/ulist.ts +4 -3
  19. package/src/parser/inline/annotation.test.ts +2 -2
  20. package/src/parser/inline/annotation.ts +3 -4
  21. package/src/parser/inline/comment.test.ts +44 -44
  22. package/src/parser/inline/comment.ts +3 -3
  23. package/src/parser/inline/deletion.ts +3 -3
  24. package/src/parser/inline/emphasis.test.ts +5 -4
  25. package/src/parser/inline/emphasis.ts +8 -3
  26. package/src/parser/inline/emstrong.ts +14 -6
  27. package/src/parser/inline/extension/index.test.ts +4 -4
  28. package/src/parser/inline/extension/placeholder.test.ts +4 -4
  29. package/src/parser/inline/html.test.ts +5 -2
  30. package/src/parser/inline/html.ts +10 -14
  31. package/src/parser/inline/insertion.ts +3 -3
  32. package/src/parser/inline/link.test.ts +2 -2
  33. package/src/parser/inline/link.ts +3 -4
  34. package/src/parser/inline/mark.test.ts +5 -4
  35. package/src/parser/inline/mark.ts +3 -3
  36. package/src/parser/inline/reference.test.ts +5 -5
  37. package/src/parser/inline/reference.ts +7 -9
  38. package/src/parser/inline/strong.test.ts +5 -4
  39. package/src/parser/inline/strong.ts +7 -3
  40. package/src/parser/inline.test.ts +2 -2
  41. package/src/parser/source/escapable.test.ts +4 -3
  42. package/src/parser/source/escapable.ts +3 -3
  43. package/src/parser/source/text.test.ts +4 -4
  44. package/src/parser/source/text.ts +3 -3
  45. package/src/parser/source/unescapable.test.ts +4 -3
  46. package/src/parser/source/unescapable.ts +3 -3
  47. package/src/parser/util.ts +26 -13
  48. package/src/renderer/render/media/image.ts +3 -3
  49. package/src/renderer/render/media/video.ts +2 -2
@@ -2,15 +2,15 @@ import { DeletionParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { blank } from '../util';
5
+ import { blankWith } from '../util';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const deletion: DeletionParser = lazy(() => creator(surround(
10
10
  str('~~'),
11
11
  some(union([
12
- some(inline, blank(/\n/, '~~')),
13
- open(/^\n/, some(inline, '~'), true),
12
+ some(inline, blankWith('\n', '~~')),
13
+ open('\n', some(inline, '~'), true),
14
14
  ])),
15
15
  str('~~'), false,
16
16
  ([, bs], rest) => [[html('del', defrag(bs))], rest],
@@ -9,10 +9,11 @@ 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>', '*'], '']);
14
- assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a', ' ', '*'], '']);
15
- assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a', '<span class="linebreak"> </span>', '*'], '']);
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\\ *')), [['*', 'a'], '\\ *']);
16
+ assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a'], '\\\n*']);
16
17
  assert.deepStrictEqual(inspect(parser('*a**b')), [['*', 'a', '**', 'b'], '']);
17
18
  assert.deepStrictEqual(inspect(parser('*a**b*')), [['*', 'a', '**', 'b', '*'], '']);
18
19
  assert.deepStrictEqual(inspect(parser('* *')), undefined);
@@ -1,9 +1,10 @@
1
1
  import { EmphasisParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
+ import { emstrong } from './emstrong';
4
5
  import { strong } from './strong';
5
6
  import { str } from '../source';
6
- import { startTight, blank } from '../util';
7
+ import { startTight, blankWith } from '../util';
7
8
  import { html, defrag } from 'typed-dom/dom';
8
9
  import { unshift } from 'spica/array';
9
10
 
@@ -11,8 +12,12 @@ export const emphasis: EmphasisParser = lazy(() => creator(surround(
11
12
  str('*'),
12
13
  startTight(some(union([
13
14
  strong,
14
- some(inline, blank('', '*')),
15
- open(some(inline, '*'), inline),
15
+ some(inline, blankWith('*')),
16
+ open(some(inline, '*'), union([
17
+ emstrong,
18
+ strong,
19
+ emphasis,
20
+ ])),
16
21
  ])), '*'),
17
22
  str('*'), false,
18
23
  ([, bs], rest) => [[html('em', defrag(bs))], rest],
@@ -4,25 +4,33 @@ import { Result, IntermediateParser } from '../../combinator/data/parser';
4
4
  import { union, some, creator, surround, open, lazy, bind } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
+ import { emphasis } from './emphasis';
7
8
  import { str } from '../source';
8
- import { startTight, blank } from '../util';
9
+ import { startTight, blankWith } from '../util';
9
10
  import { html, defrag } from 'typed-dom/dom';
10
11
  import { unshift } from 'spica/array';
11
12
 
12
13
  const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
13
- some(inline, blank('', '**')),
14
- open(some(inline, '*'), inline),
14
+ some(inline, blankWith('**')),
15
+ open(some(inline, '*'), union([
16
+ emstrong,
17
+ strong,
18
+ ])),
15
19
  ])));
16
20
  const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
17
21
  strong,
18
- some(inline, blank('', '*')),
19
- open(some(inline, '*'), inline),
22
+ some(inline, blankWith('*')),
23
+ open(some(inline, '*'), union([
24
+ emstrong,
25
+ strong,
26
+ emphasis,
27
+ ])),
20
28
  ])));
21
29
 
22
30
  export const emstrong: EmStrongParser = lazy(() => creator(surround(
23
31
  str('***'),
24
32
  startTight(some(union([
25
- some(inline, blank('', '*')),
33
+ some(inline, blankWith('*')),
26
34
  open(some(inline, '*'), inline),
27
35
  ]))),
28
36
  str(/^\*{1,3}/), false,
@@ -45,7 +45,7 @@ describe('Unit: parser/inline/extension/index', () => {
45
45
  assert.deepStrictEqual(inspect(parser('[#a \\ ]')), [['<a class="index" href="#index:a">a</a>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;]')), [['<a class="index" href="#index:a">a</a>'], '']);
47
47
  assert.deepStrictEqual(inspect(parser('[#a <wbr>]')), [['<a class="index" href="#index:a">a</a>'], '']);
48
- assert.deepStrictEqual(inspect(parser('[#a [# b #]]')), [['<a class="index" href="#index:a">a <span class="comment"><input type="checkbox"><span>[# b #]</span></span></a>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('[#a [% b %]]')), [['<a class="index" href="#index:a">a <span class="comment"><input type="checkbox"><span>[% b %]</span></span></a>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('[#a\\ ]')), [['<a class="index" href="#index:a">a</a>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser('[#a\\ b]')), [['<a class="index" href="#index:a_b">a b</a>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser('[#[]]')), [['<a class="index" href="#index:[]">[]</a>'], '']);
@@ -61,8 +61,8 @@ describe('Unit: parser/inline/extension/index', () => {
61
61
  assert.deepStrictEqual(inspect(parser('[#@a]')), [['<a class="index" href="#index:@a">@a</a>'], '']);
62
62
  assert.deepStrictEqual(inspect(parser('[#http://host]')), [['<a class="index" href="#index:http://host">http://host</a>'], '']);
63
63
  assert.deepStrictEqual(inspect(parser('[#!http://host]')), [['<a class="index" href="#index:!http://host">!http://host</a>'], '']);
64
- assert.deepStrictEqual(inspect(parser('[#[# #]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[# #]</span></span></a>'], '']);
65
- assert.deepStrictEqual(inspect(parser('[#[# a #]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[# a #]</span></span></a>'], '']);
64
+ assert.deepStrictEqual(inspect(parser('[#[% %]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[% %]</span></span></a>'], '']);
65
+ assert.deepStrictEqual(inspect(parser('[#[% a %]]')), [['<a class="index"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></a>'], '']);
66
66
  assert.deepStrictEqual(inspect(parser('[#a((b))]')), [['<a class="index" href="#index:a((b))">a<span class="paren">((b))</span></a>'], '']);
67
67
  assert.deepStrictEqual(inspect(parser('[#a[[b]]]')), [['<a class="index" href="#index:a[[b]]">a[[b]]</a>'], '']);
68
68
  });
@@ -89,7 +89,7 @@ describe('Unit: parser/inline/extension/index', () => {
89
89
  assert.deepStrictEqual(inspect(parser('[#a \\ |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
90
90
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
91
91
  assert.deepStrictEqual(inspect(parser('[#a <wbr>|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
92
- 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>'], '']);
92
+ 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>'], '']);
93
93
  assert.deepStrictEqual(inspect(parser('[#a\\ |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
94
94
  });
95
95
 
@@ -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"><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>'], '']);
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"><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>'], '']);
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
  });
@@ -29,11 +29,12 @@ describe('Unit: parser/inline/html', () => {
29
29
  assert.deepStrictEqual(inspect(parser('<small>z')), undefined);
30
30
  assert.deepStrictEqual(inspect(parser('<small></small>')), undefined);
31
31
  assert.deepStrictEqual(inspect(parser('<small> </small>')), undefined);
32
+ assert.deepStrictEqual(inspect(parser('<small>\\ </small>')), undefined);
33
+ assert.deepStrictEqual(inspect(parser('<small>&Tab;</small>')), undefined);
34
+ assert.deepStrictEqual(inspect(parser('<small><wbr></small>')), undefined);
32
35
  assert.deepStrictEqual(inspect(parser('<small>\n</small>')), undefined);
33
36
  assert.deepStrictEqual(inspect(parser('<small>\na</small>')), undefined);
34
- assert.deepStrictEqual(inspect(parser('<small>\\ a</small>')), undefined);
35
37
  assert.deepStrictEqual(inspect(parser('<small>\\\na</small>')), undefined);
36
- assert.deepStrictEqual(inspect(parser('<small><wbr></small>')), undefined);
37
38
  assert.deepStrictEqual(inspect(parser('<small>a')), undefined);
38
39
  assert.deepStrictEqual(inspect(parser('<small>a</BDO>')), undefined);
39
40
  assert.deepStrictEqual(inspect(parser('<SMALL>a</SMALL>')), undefined);
@@ -60,6 +61,8 @@ describe('Unit: parser/inline/html', () => {
60
61
  assert.deepStrictEqual(inspect(parser('<small> a</small>')), [['<small> a</small>'], '']);
61
62
  assert.deepStrictEqual(inspect(parser('<small> a </small>')), [['<small> a </small>'], '']);
62
63
  assert.deepStrictEqual(inspect(parser('<small> a </small>')), [['<small> a </small>'], '']);
64
+ assert.deepStrictEqual(inspect(parser('<small>\\ a</small>')), [['<small> a</small>'], '']);
65
+ assert.deepStrictEqual(inspect(parser('<small><wbr>a</small>')), [['<small><wbr>a</small>'], '']);
63
66
  assert.deepStrictEqual(inspect(parser('<small>a</small>')), [['<small>a</small>'], '']);
64
67
  assert.deepStrictEqual(inspect(parser('<small>a</small>a')), [['<small>a</small>'], 'a']);
65
68
  assert.deepStrictEqual(inspect(parser('<small>a </small>')), [['<small>a </small>'], '']);
@@ -1,10 +1,9 @@
1
- import { undefined } from 'spica/global';
2
- import { isFrozen, ObjectEntries } from 'spica/alias';
1
+ import { undefined, Object } from 'spica/global';
3
2
  import { HTMLParser } from '../inline';
4
3
  import { union, some, validate, creator, surround, open, match, lazy } from '../../combinator';
5
4
  import { inline } from '../inline';
6
5
  import { str } from '../source';
7
- import { startLoose, blank } from '../util';
6
+ import { startLoose, blankWith } from '../util';
8
7
  import { html as h, defrag } from 'typed-dom/dom';
9
8
  import { memoize } from 'spica/memoize';
10
9
  import { Cache } from 'spica/cache';
@@ -36,12 +35,11 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
36
35
  surround<HTMLParser.TagParser, string>(surround(
37
36
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
38
37
  startLoose(some(union([
39
- some(inline, blank(/\n/, `</${tag}>`)),
40
- open(/^\n/, some(inline, `</${tag}>`), true),
41
- ]), `</${tag}>`), `</${tag}>`),
38
+ open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`)), true),
39
+ ])), `</${tag}>`),
42
40
  str(`</${tag}>`), false,
43
41
  ([as, bs, cs], rest) =>
44
- [[elem(tag, as, defrag(bs), cs)], rest]),
42
+ [[elem(tag, as, bs, cs)], rest]),
45
43
  ([, tag]) => tags.indexOf(tag), [])),
46
44
  match(
47
45
  /^(?=<([a-z]+)(?=[^\S\n]|>))/,
@@ -50,12 +48,11 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
50
48
  surround<HTMLParser.TagParser, string>(surround(
51
49
  str(`<${tag}`), some(attribute), str(/^\s*>/), true),
52
50
  startLoose(some(union([
53
- some(inline, blank(/\n/, `</${tag}>`)),
54
- open(/^\n/, some(inline, `</${tag}>`), true),
55
- ]), `</${tag}>`), `</${tag}>`),
51
+ open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`)), true),
52
+ ])), `</${tag}>`),
56
53
  str(`</${tag}>`), false,
57
54
  ([as, bs, cs], rest) =>
58
- [[elem(tag, as, defrag(bs), cs)], rest]),
55
+ [[elem(tag, as, bs, cs)], rest]),
59
56
  ([, tag]) => tag,
60
57
  new Cache(10000))),
61
58
  ])))));
@@ -67,13 +64,12 @@ export const attribute: HTMLParser.TagParser.AttributeParser = union([
67
64
  function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[]): HTMLElement {
68
65
  assert(as.length > 0);
69
66
  assert(as[0][0] === '<' && as[as.length - 1].slice(-1) === '>');
70
- assert(bs.length === defrag(bs).length);
71
67
  assert(cs.length === 1);
72
68
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag <${tag}>`, as, bs, cs);
73
69
  const attrs = attributes('html', [], attrspec[tag], as.slice(1, -1));
74
70
  return 'data-invalid-syntax' in attrs
75
71
  ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs)
76
- : h(tag as 'span', attrs, bs);
72
+ : h(tag as 'span', attrs, defrag(bs));
77
73
  }
78
74
  function invalid(type: string, message: string, as: (HTMLElement | string)[], bs: (HTMLElement | string)[], cs: (HTMLElement | string)[]): HTMLElement {
79
75
  return h('span', {
@@ -86,7 +82,7 @@ function invalid(type: string, message: string, as: (HTMLElement | string)[], bs
86
82
 
87
83
  const requiredAttributes = memoize(
88
84
  (spec: Readonly<Record<string, readonly (string | undefined)[] | undefined>>) =>
89
- ObjectEntries(spec).flatMap(([k, v]) => v && isFrozen(v) ? [k] : []),
85
+ Object.entries(spec).flatMap(([k, v]) => v && Object.isFrozen(v) ? [k] : []),
90
86
  new WeakMap());
91
87
 
92
88
  export function attributes(
@@ -2,15 +2,15 @@ import { InsertionParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { blank } from '../util';
5
+ import { blankWith } from '../util';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const insertion: InsertionParser = lazy(() => creator(surround(
10
10
  str('++'),
11
11
  some(union([
12
- some(inline, blank(/\n/, '++')),
13
- open(/^\n/, some(inline, '+'), true),
12
+ some(inline, blankWith('\n', '++')),
13
+ open('\n', some(inline, '+'), true),
14
14
  ])),
15
15
  str('++'), false,
16
16
  ([, bs], rest) => [[html('ins', defrag(bs))], rest],
@@ -67,8 +67,6 @@ describe('Unit: parser/inline/link', () => {
67
67
  assert.deepStrictEqual(inspect(parser('[[]{b}')), undefined);
68
68
  assert.deepStrictEqual(inspect(parser('[]]{b}')), undefined);
69
69
  assert.deepStrictEqual(inspect(parser('[a]{}')), undefined);
70
- assert.deepStrictEqual(inspect(parser('[\\ a]{b}')), undefined);
71
- assert.deepStrictEqual(inspect(parser('[ \\ a]{b}')), undefined);
72
70
  assert.deepStrictEqual(inspect(parser('[a\nb]{b}')), undefined);
73
71
  assert.deepStrictEqual(inspect(parser('[a\\\nb]{b}')), undefined);
74
72
  assert.deepStrictEqual(inspect(parser('[<wbr>]{b}')), undefined);
@@ -118,6 +116,8 @@ describe('Unit: parser/inline/link', () => {
118
116
  assert.deepStrictEqual(inspect(parser('[]{^/b}', { host: new URL('/0.0,0.0,0z', location.origin) })), [[`<a href="/0.0,0.0,0z/b">^/b</a>`], '']);
119
117
  assert.deepStrictEqual(inspect(parser('[ a]{b}')), [['<a href="b">a</a>'], '']);
120
118
  assert.deepStrictEqual(inspect(parser('[ a ]{b}')), [['<a href="b">a</a>'], '']);
119
+ assert.deepStrictEqual(inspect(parser('[\\ a]{b}')), [['<a href="b">a</a>'], '']);
120
+ assert.deepStrictEqual(inspect(parser('[ \\ a]{b}')), [['<a href="b">a</a>'], '']);
121
121
  assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
122
122
  assert.deepStrictEqual(inspect(parser('[a ]{b}')), [['<a href="b">a</a>'], '']);
123
123
  assert.deepStrictEqual(inspect(parser('[a]{b}')), [['<a href="b">a</a>'], '']);
@@ -6,7 +6,7 @@ import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { autolink } from '../autolink';
8
8
  import { str } from '../source';
9
- import { startLoose, trimSpaceStart, trimNodeEnd, stringify } from '../util';
9
+ import { trimBlank, stringify } from '../util';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
  import { ReadonlyURL } from 'spica/url';
12
12
 
@@ -26,7 +26,6 @@ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}',
26
26
  surround('[', shortmedia, ']'),
27
27
  surround(
28
28
  '[',
29
- startLoose(
30
29
  context({ syntax: { inline: {
31
30
  annotation: false,
32
31
  reference: false,
@@ -37,7 +36,7 @@ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}',
37
36
  media: false,
38
37
  autolink: false,
39
38
  }}},
40
- trimSpaceStart(some(inline, ']', /^\\?\n/)))),
39
+ trimBlank(some(inline, ']', /^\\?\n/))),
41
40
  ']',
42
41
  true),
43
42
  ]))),
@@ -52,7 +51,7 @@ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}',
52
51
  assert(!INSECURE_URI.match(/\s/));
53
52
  const el = elem(
54
53
  INSECURE_URI,
55
- trimNodeEnd(defrag(content)),
54
+ defrag(content),
56
55
  new ReadonlyURL(
57
56
  resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
58
57
  context.host?.href || location.href),
@@ -12,10 +12,11 @@ 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>', '=='], '']);
17
- assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a', ' ', '=='], '']);
18
- assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a', '<span class="linebreak"> </span>', '=='], '']);
15
+ assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a'], ' ==']);
16
+ assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' '], ' ==']);
17
+ assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a'], '\n==']);
18
+ assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a'], '\\ ==']);
19
+ assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a'], '\\\n==']);
19
20
  assert.deepStrictEqual(inspect(parser('== ==')), undefined);
20
21
  assert.deepStrictEqual(inspect(parser('== a==')), undefined);
21
22
  assert.deepStrictEqual(inspect(parser('== a ==')), undefined);
@@ -2,15 +2,15 @@ import { MarkParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { startTight, blank } from '../util';
5
+ import { startTight, blankWith } from '../util';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const mark: MarkParser = lazy(() => creator(surround(
10
10
  str('=='),
11
11
  startTight(some(union([
12
- some(inline, blank('', '==')),
13
- open(some(inline, '='), inline),
12
+ some(inline, blankWith('==')),
13
+ open(some(inline, '='), mark),
14
14
  ]))),
15
15
  str('=='), false,
16
16
  ([, bs], rest) => [[html('mark', defrag(bs))], rest],
@@ -16,9 +16,7 @@ describe('Unit: parser/inline/reference', () => {
16
16
  assert.deepStrictEqual(inspect(parser('[[ ]]')), undefined);
17
17
  assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
18
18
  assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
19
- assert.deepStrictEqual(inspect(parser('[[\\ a]]')), undefined);
20
19
  assert.deepStrictEqual(inspect(parser('[[\\\na]]')), undefined);
21
- assert.deepStrictEqual(inspect(parser('[[<wbr>a]]')), undefined);
22
20
  assert.deepStrictEqual(inspect(parser('[[a\n]]')), undefined);
23
21
  assert.deepStrictEqual(inspect(parser('[[a\\\n]]')), undefined);
24
22
  assert.deepStrictEqual(inspect(parser('[[a\nb]]')), undefined);
@@ -33,6 +31,8 @@ describe('Unit: parser/inline/reference', () => {
33
31
  it('basic', () => {
34
32
  assert.deepStrictEqual(inspect(parser('[[ a]]')), [['<sup class="reference">a</sup>'], '']);
35
33
  assert.deepStrictEqual(inspect(parser('[[ a ]]')), [['<sup class="reference">a</sup>'], '']);
34
+ assert.deepStrictEqual(inspect(parser('[[\\ a]]')), [['<sup class="reference">a</sup>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('[[<wbr>a]]')), [['<sup class="reference">a</sup>'], '']);
36
36
  assert.deepStrictEqual(inspect(parser('[[a]]')), [['<sup class="reference">a</sup>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
38
38
  assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
@@ -68,8 +68,8 @@ describe('Unit: parser/inline/reference', () => {
68
68
  assert.deepStrictEqual(inspect(parser('[[^a|b]]')), [['<sup class="reference" data-abbr="a">b</sup>'], '']);
69
69
  assert.deepStrictEqual(inspect(parser('[[^a|b ]]')), [['<sup class="reference" data-abbr="a">b</sup>'], '']);
70
70
  assert.deepStrictEqual(inspect(parser('[[^a|b ]]')), [['<sup class="reference" data-abbr="a">b</sup>'], '']);
71
- assert.deepStrictEqual(inspect(parser('[[^a|<wbr>]]')), [['<sup class="invalid">^a|</sup>'], '']);
72
- assert.deepStrictEqual(inspect(parser('[[^a|<wbr>b]]')), [['<sup class="invalid">^a|<wbr>b</sup>'], '']);
71
+ assert.deepStrictEqual(inspect(parser('[[^a|<wbr>]]')), [['<sup class="reference" data-abbr="a"></sup>'], '']);
72
+ assert.deepStrictEqual(inspect(parser('[[^a|<wbr>b]]')), [['<sup class="reference" data-abbr="a">b</sup>'], '']);
73
73
  assert.deepStrictEqual(inspect(parser('[[^a|^b]]')), [['<sup class="reference" data-abbr="a">^b</sup>'], '']);
74
74
  assert.deepStrictEqual(inspect(parser('[[^a| ]]')), [['<sup class="reference" data-abbr="a"></sup>'], '']);
75
75
  assert.deepStrictEqual(inspect(parser('[[^a| b]]')), [['<sup class="reference" data-abbr="a">b</sup>'], '']);
@@ -87,7 +87,7 @@ describe('Unit: parser/inline/reference', () => {
87
87
  assert.deepStrictEqual(inspect(parser(`[[^A's, Aces']]`)), [[`<sup class="reference" data-abbr="A's, Aces'"></sup>`], '']);
88
88
  assert.deepStrictEqual(inspect(parser('[[^^]]')), [['<sup class="invalid">^^</sup>'], '']);
89
89
  assert.deepStrictEqual(inspect(parser('[[\\^]]')), [['<sup class="reference">^</sup>'], '']);
90
- assert.deepStrictEqual(inspect(parser('[[^ ]]')), [['<sup class="invalid">^</sup>'], '']);
90
+ assert.deepStrictEqual(inspect(parser('[[^ ]]')), [['<sup class="invalid">^ </sup>'], '']);
91
91
  assert.deepStrictEqual(inspect(parser('[[^ a]]')), [['<sup class="invalid">^ a</sup>'], '']);
92
92
  assert.deepStrictEqual(inspect(parser('[[^ |]]')), [['<sup class="invalid">^ |</sup>'], '']);
93
93
  assert.deepStrictEqual(inspect(parser('[[^ |b]]')), [['<sup class="invalid">^ |b</sup>'], '']);
@@ -1,15 +1,14 @@
1
1
  import { undefined } from 'spica/global';
2
2
  import { ReferenceParser } from '../inline';
3
- import { union, subsequence, some, validate, verify, focus, guard, context, creator, surround, lazy, fmap } from '../../combinator';
3
+ import { union, subsequence, some, validate, focus, guard, context, creator, surround, lazy, fmap, bind } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
- import { startLoose, isStartLoose, trimSpaceStart, trimNodeEnd, stringify } from '../util';
6
+ import { regBlankStart, trimBlank, stringify } from '../util';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
9
  export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
10
10
  '[[',
11
11
  guard(context => context.syntax?.inline?.reference ?? true,
12
- startLoose(
13
12
  context({ syntax: { inline: {
14
13
  annotation: false,
15
14
  reference: false,
@@ -23,17 +22,16 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
23
22
  subsequence([
24
23
  abbr,
25
24
  focus(/^\^[^\S\n]*/, source => [['', source], '']),
26
- trimSpaceStart(some(inline, ']', /^\\?\n/)),
27
- ])))),
25
+ trimBlank(some(inline, ']', /^\\?\n/)),
26
+ ]))),
28
27
  ']]'),
29
- ns => [html('sup', attributes(ns), trimNodeEnd(defrag(ns)))]))));
28
+ ns => [html('sup', attributes(ns), defrag(ns))]))));
30
29
 
31
- const abbr: ReferenceParser.AbbrParser = creator(fmap(verify(surround(
30
+ const abbr: ReferenceParser.AbbrParser = creator(bind(surround(
32
31
  '^',
33
32
  union([str(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]),
34
33
  /^\|?(?=]])|^\|[^\S\n]*/),
35
- (_, rest, context) => isStartLoose(rest, context)),
36
- ([source]) => [html('abbr', source)]));
34
+ ([source], rest) => [[html('abbr', source)], rest.replace(regBlankStart, '')]));
37
35
 
38
36
  function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
39
37
  return typeof ns[0] === 'object' && ns[0].tagName === 'ABBR'
@@ -9,10 +9,11 @@ describe('Unit: parser/inline/strong', () => {
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>', '**'], '']);
14
- assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' ', '**'], '']);
15
- assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>', '**'], '']);
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\\ **')), [['**', 'a'], '\\ **']);
16
+ assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a'], '\\\n**']);
16
17
  assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
17
18
  assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
18
19
  assert.deepStrictEqual(inspect(parser('** **')), undefined);
@@ -1,16 +1,20 @@
1
1
  import { StrongParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
+ import { emstrong } from './emstrong';
4
5
  import { str } from '../source';
5
- import { startTight, blank } from '../util';
6
+ import { startTight, blankWith } from '../util';
6
7
  import { html, defrag } from 'typed-dom/dom';
7
8
  import { unshift } from 'spica/array';
8
9
 
9
10
  export const strong: StrongParser = lazy(() => creator(surround(
10
11
  str('**'),
11
12
  startTight(some(union([
12
- some(inline, blank('', '**')),
13
- open(some(inline, '*'), inline),
13
+ some(inline, blankWith('**')),
14
+ open(some(inline, '*'), union([
15
+ emstrong,
16
+ strong,
17
+ ])),
14
18
  ])), '*'),
15
19
  str('**'), false,
16
20
  ([, bs], rest) => [[html('strong', defrag(bs))], rest],
@@ -166,8 +166,8 @@ describe('Unit: parser/inline', () => {
166
166
  assert.deepStrictEqual(inspect(parser('[#a*b\nc*]')), [['[', '<a href="/hashtags/a" class="hashtag">#a</a>', '<em>b<br>c</em>', ']'], '']);
167
167
  assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), [['[', '<em>a<br>b</em>', ']', '<a href="/">/</a>'], '']);
168
168
  assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['[', '[', '<em>a<br>b</em>', ']', ']'], '']);
169
- assert.deepStrictEqual(inspect(parser('"[# *"*"*')), [['"', '[#', ' ', '*', '"', '*', '"', '*'], '']);
170
- assert.deepStrictEqual(inspect(parser('"[# "*"* #]')), [['"', '[#', ' ', '"', '*', '"', '*', ' ', '#', ']'], '']);
169
+ assert.deepStrictEqual(inspect(parser('"[% *"*"*')), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
170
+ assert.deepStrictEqual(inspect(parser('"[% "*"* %]')), [['"', '[%', ' ', '"', '*', '"', '*', ' ', '%', ']'], '']);
171
171
  });
172
172
 
173
173
  it('uri', () => {
@@ -18,10 +18,11 @@ describe('Unit: parser/source/escsource', () => {
18
18
 
19
19
  it('space', () => {
20
20
  assert.deepStrictEqual(inspect(parser(' ')), [[' '], '']);
21
- assert.deepStrictEqual(inspect(parser(' ')), [[' '], '']);
22
- assert.deepStrictEqual(inspect(parser(' ')), [[' '], '']);
21
+ assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
22
+ assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
23
23
  assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
24
- assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
24
+ assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
25
+ assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
25
26
  });
26
27
 
27
28
  it('linebreak', () => {
@@ -2,11 +2,11 @@ import { EscapableSourceParser } from '../source';
2
2
  import { creator } from '../../combinator';
3
3
  import { nonWhitespace } from './text';
4
4
 
5
- const separator = /[\s\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/;
5
+ const delimiter = /[\s\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/;
6
6
 
7
7
  export const escsource: EscapableSourceParser = creator(source => {
8
8
  if (source === '') return;
9
- const i = source.search(separator);
9
+ const i = source.search(delimiter);
10
10
  switch (i) {
11
11
  case -1:
12
12
  return [[source], ''];
@@ -22,7 +22,7 @@ export const escsource: EscapableSourceParser = creator(source => {
22
22
  ? source.search(nonWhitespace)
23
23
  : 1;
24
24
  assert(i > 0);
25
- return [[source.slice(0, i)], source.slice(i)];
25
+ return [[source.slice(0, i - +b || 1)], source.slice(i - +b || 1)];
26
26
  }
27
27
  default:
28
28
  return [[source.slice(0, i)], source.slice(i)];
@@ -26,8 +26,8 @@ describe('Unit: parser/text/text', () => {
26
26
  assert.deepStrictEqual(inspect(parser(' \\\n')), [['<span class="linebreak"> </span>'], '']);
27
27
  assert.deepStrictEqual(inspect(parser(' \\\n')), [['<span class="linebreak"> </span>'], '']);
28
28
  assert.deepStrictEqual(inspect(parser(' a')), [[' ', 'a'], '']);
29
- assert.deepStrictEqual(inspect(parser(' a')), [[' ', 'a'], '']);
30
- assert.deepStrictEqual(inspect(parser(' a')), [[' ', 'a'], '']);
29
+ assert.deepStrictEqual(inspect(parser(' a')), [[' ', ' ', 'a'], '']);
30
+ assert.deepStrictEqual(inspect(parser(' a')), [[' ', ' ', 'a'], '']);
31
31
  assert.deepStrictEqual(inspect(parser('a ')), [['a'], '']);
32
32
  assert.deepStrictEqual(inspect(parser('a ')), [['a'], '']);
33
33
  assert.deepStrictEqual(inspect(parser('a \n')), [['a', '<br>'], '']);
@@ -35,8 +35,8 @@ describe('Unit: parser/text/text', () => {
35
35
  assert.deepStrictEqual(inspect(parser('a \\\n')), [['a', '<span class="linebreak"> </span>'], '']);
36
36
  assert.deepStrictEqual(inspect(parser('a \\\n')), [['a', '<span class="linebreak"> </span>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser('a b')), [['a', ' ', 'b'], '']);
38
- assert.deepStrictEqual(inspect(parser('a b')), [['a', ' ', 'b'], '']);
39
- assert.deepStrictEqual(inspect(parser('a b')), [['a', ' ', 'b'], '']);
38
+ assert.deepStrictEqual(inspect(parser('a b')), [['a', ' ', ' ', 'b'], '']);
39
+ assert.deepStrictEqual(inspect(parser('a b')), [['a', ' ', ' ', 'b'], '']);
40
40
  });
41
41
 
42
42
  it('hardbreak', () => {
@@ -4,14 +4,14 @@ import { union, focus, creator } from '../../combinator';
4
4
  import { str } from './str';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
7
- export const separator = /[\s\x00-\x7F]|\S#|[、。!?][^\S\n]*(?=\\\n)/;
7
+ export const delimiter = /[\s\x00-\x7F]|\S#|[、。!?][^\S\n]*(?=\\\n)/;
8
8
  export const nonWhitespace = /[\S\n]|$/;
9
9
  export const nonAlphanumeric = /[^0-9A-Za-z]|\S#|$/;
10
10
  const repeat = str(/^(.)\1*/);
11
11
 
12
12
  export const text: TextParser = creator((source, context) => {
13
13
  if (source === '') return;
14
- const i = source.search(separator);
14
+ const i = source.search(delimiter);
15
15
  switch (i) {
16
16
  case -1:
17
17
  return [[source], ''];
@@ -70,7 +70,7 @@ export const text: TextParser = creator((source, context) => {
70
70
  || b && source[i] === '\n'
71
71
  || b && source[i] === '\\' && source[i + 1] === '\n'
72
72
  ? [[], source.slice(i)]
73
- : [[source.slice(0, i)], source.slice(i)];
73
+ : [[source.slice(0, i - +b || 1)], source.slice(i - +b || 1)];
74
74
  }
75
75
  default:
76
76
  return [[source.slice(0, i)], source.slice(i)];