securemark 0.217.0 → 0.218.3

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 (54) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/securemark.js +166 -143
  3. package/markdown.d.ts +7 -6
  4. package/package-lock.json +7 -7
  5. package/package.json +1 -1
  6. package/src/parser/api/bind.test.ts +5 -5
  7. package/src/parser/api/bind.ts +2 -2
  8. package/src/parser/api/parse.test.ts +18 -0
  9. package/src/parser/api/parse.ts +2 -2
  10. package/src/parser/block/blockquote.test.ts +1 -1
  11. package/src/parser/block/extension/example.test.ts +1 -1
  12. package/src/parser/block/extension/fig.ts +1 -1
  13. package/src/parser/block/extension/table.ts +2 -2
  14. package/src/parser/block/heading.test.ts +10 -12
  15. package/src/parser/block/ilist.ts +8 -1
  16. package/src/parser/block/paragraph.test.ts +7 -0
  17. package/src/parser/function/footnote.test.ts +16 -16
  18. package/src/parser/function/footnote.ts +1 -1
  19. package/src/parser/inline/annotation.test.ts +5 -2
  20. package/src/parser/inline/annotation.ts +4 -5
  21. package/src/parser/inline/comment.ts +1 -1
  22. package/src/parser/inline/deletion.test.ts +1 -0
  23. package/src/parser/inline/deletion.ts +2 -1
  24. package/src/parser/inline/emphasis.ts +5 -5
  25. package/src/parser/inline/emstrong.ts +4 -4
  26. package/src/parser/inline/extension/index.test.ts +25 -7
  27. package/src/parser/inline/extension/index.ts +17 -14
  28. package/src/parser/inline/extension/indexee.ts +1 -1
  29. package/src/parser/inline/extension/indexer.test.ts +2 -0
  30. package/src/parser/inline/extension/indexer.ts +5 -3
  31. package/src/parser/inline/extension/placeholder.test.ts +10 -10
  32. package/src/parser/inline/extension/placeholder.ts +13 -9
  33. package/src/parser/inline/html.test.ts +2 -1
  34. package/src/parser/inline/html.ts +16 -22
  35. package/src/parser/inline/insertion.test.ts +1 -0
  36. package/src/parser/inline/insertion.ts +2 -1
  37. package/src/parser/inline/link.test.ts +3 -7
  38. package/src/parser/inline/link.ts +9 -9
  39. package/src/parser/inline/mark.test.ts +1 -0
  40. package/src/parser/inline/mark.ts +2 -2
  41. package/src/parser/inline/math.ts +2 -2
  42. package/src/parser/inline/media.test.ts +3 -7
  43. package/src/parser/inline/media.ts +5 -5
  44. package/src/parser/inline/reference.test.ts +24 -9
  45. package/src/parser/inline/reference.ts +9 -9
  46. package/src/parser/inline/ruby.test.ts +2 -1
  47. package/src/parser/inline/ruby.ts +12 -10
  48. package/src/parser/inline/strong.ts +5 -5
  49. package/src/parser/segment.ts +11 -17
  50. package/src/parser/source/escapable.ts +1 -0
  51. package/src/parser/source/str.ts +3 -5
  52. package/src/parser/source/text.ts +8 -6
  53. package/src/parser/source/unescapable.ts +1 -0
  54. package/src/parser/util.ts +85 -60
package/markdown.d.ts CHANGED
@@ -707,21 +707,21 @@ export namespace MarkdownParser {
707
707
  // [#index]
708
708
  Inline<'extension/index'>,
709
709
  Parser<HTMLAnchorElement, Context, [
710
+ IndexParser.SignatureParser,
710
711
  InlineParser,
711
- IndexParser.IndexerParser,
712
712
  ]> {
713
713
  }
714
714
  export namespace IndexParser {
715
- export interface IndexerParser extends
716
- Inline<'extension/index/indexer'>,
715
+ export interface SignatureParser extends
716
+ Inline<'extension/index/signature'>,
717
717
  Parser<HTMLElement, Context, [
718
- IndexerParser.BracketParser,
718
+ SignatureParser.BracketParser,
719
719
  SourceParser.TxtParser,
720
720
  ]> {
721
721
  }
722
- export namespace IndexerParser {
722
+ export namespace SignatureParser {
723
723
  export interface BracketParser extends
724
- Inline<'extension/index/indexer/bracket'>,
724
+ Inline<'extension/index/signature/bracket'>,
725
725
  Parser<string, Context, [
726
726
  Parser<string, Context, [
727
727
  BracketParser,
@@ -826,6 +826,7 @@ export namespace MarkdownParser {
826
826
  SourceParser.StrParser,
827
827
  SourceParser.StrParser,
828
828
  SourceParser.StrParser,
829
+ SourceParser.StrParser,
829
830
  ]> {
830
831
  }
831
832
  }
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.217.0",
3
+ "version": "0.218.3",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -2968,9 +2968,9 @@
2968
2968
  "dev": true
2969
2969
  },
2970
2970
  "electron-to-chromium": {
2971
- "version": "1.3.861",
2972
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.861.tgz",
2973
- "integrity": "sha512-GZyflmpMnZRdZ1e2yAyvuFwz1MPSVQelwHX4TJZyXypB8NcxdPvPNwy5lOTxnlkrK13EiQzyTPugRSnj6cBgKg==",
2971
+ "version": "1.3.864",
2972
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz",
2973
+ "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==",
2974
2974
  "dev": true
2975
2975
  },
2976
2976
  "elliptic": {
@@ -8649,9 +8649,9 @@
8649
8649
  }
8650
8650
  },
8651
8651
  "prompts": {
8652
- "version": "2.4.1",
8653
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz",
8654
- "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==",
8652
+ "version": "2.4.2",
8653
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
8654
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
8655
8655
  "dev": true,
8656
8656
  "requires": {
8657
8657
  "kleur": "^3.0.3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.217.0",
3
+ "version": "0.218.3",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -46,9 +46,9 @@ describe('Unit: parser/api/bind', () => {
46
46
  assert.deepStrictEqual(
47
47
  inspect(iter, 3),
48
48
  [
49
- '<h1 class="error" translate="no">Error: Too large segment over 100,000 in length.</h1>',
49
+ '<h1 class="error" translate="no">Error: Too large segment over 100,000 bytes.</h1>',
50
50
  `<pre class="error" translate="no">${'\n'.repeat(997)}...</pre>`,
51
- '<h1 class="error" translate="no">Error: Too large segment over 100,000 in length.</h1>',
51
+ '<h1 class="error" translate="no">Error: Too large segment over 100,000 bytes.</h1>',
52
52
  ]);
53
53
  });
54
54
 
@@ -212,15 +212,15 @@ describe('Unit: parser/api/bind', () => {
212
212
  html('ol', [
213
213
  html('li', { id: 'annotation:def:1' }, [
214
214
  '1',
215
- html('sup', [html('a', { href: '#annotation:ref:1' }, '~1')])
215
+ html('sup', [html('a', { href: '#annotation:ref:1' }, '^1')])
216
216
  ]),
217
217
  html('li', { id: 'annotation:def:2' }, [
218
218
  '2',
219
- html('sup', [html('a', { href: '#annotation:ref:2' }, '~2')])
219
+ html('sup', [html('a', { href: '#annotation:ref:2' }, '^2')])
220
220
  ]),
221
221
  html('li', { id: 'annotation:def:3' }, [
222
222
  '3',
223
- html('sup', [html('a', { href: '#annotation:ref:3' }, '~3')])
223
+ html('sup', [html('a', { href: '#annotation:ref:3' }, '^3')])
224
224
  ]),
225
225
  ]).outerHTML);
226
226
  assert.throws(() => update('').next());
@@ -5,7 +5,7 @@ import { MarkdownParser } from '../../../markdown';
5
5
  import { eval } from '../../combinator/data/parser';
6
6
  import { header } from '../header';
7
7
  import { block } from '../block';
8
- import { segment, prepare } from '../segment';
8
+ import { segment, validate, MAX_INPUT_SIZE } from '../segment';
9
9
  import { normalize } from './normalize';
10
10
  import { headers } from './header';
11
11
  import { figure } from '../function/figure';
@@ -43,7 +43,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
43
43
  function* parse(source: string): Generator<Progress, undefined, undefined> {
44
44
  if (settings.chunk && revision) throw new Error('Chunks cannot be updated.');
45
45
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
46
- source = normalize(prepare(source));
46
+ source = normalize(validate(source, MAX_INPUT_SIZE) ? source : source.slice(0, MAX_INPUT_SIZE + 1));
47
47
  context = ObjectAssign(context, { url: url ? new ReadonlyURL(url) : undefined });
48
48
  const rev = revision = Symbol();
49
49
  const sourceSegments: string[] = [];
@@ -35,9 +35,27 @@ describe('Unit: parser/api/parse', () => {
35
35
  assert.deepStrictEqual(
36
36
  [...parse('\\').children].map(el => el.outerHTML),
37
37
  ['<p>\\</p>']);
38
+ assert.deepStrictEqual(
39
+ [...parse('\\\na').children].map(el => el.outerHTML),
40
+ ['<p>\\<br>a</p>']);
38
41
  assert.deepStrictEqual(
39
42
  [...parse('&Tab;').children].map(el => el.outerHTML),
40
43
  ['<p>&amp;Tab;</p>']);
44
+ assert.deepStrictEqual(
45
+ [...parse('&Tab;\na').children].map(el => el.outerHTML),
46
+ ['<p>&amp;Tab;<br>a</p>']);
47
+ assert.deepStrictEqual(
48
+ [...parse('<wbr>').children].map(el => el.outerHTML),
49
+ ['<p>&lt;wbr&gt;</p>']);
50
+ assert.deepStrictEqual(
51
+ [...parse('<wbr>\na').children].map(el => el.outerHTML),
52
+ ['<p>&lt;wbr&gt;<br>a</p>']);
53
+ assert.deepStrictEqual(
54
+ [...parse('[#\n<wbr>\n#]').children].map(el => el.outerHTML),
55
+ ['<p>[#<br>&lt;wbr&gt;<br>#]</p>']);
56
+ assert.deepStrictEqual(
57
+ [...parse('[#\n<wbr>\n#]a').children].map(el => el.outerHTML),
58
+ ['<p><sup class="comment" title="<wbr>"></sup>a</p>']);
41
59
  });
42
60
 
43
61
  it('linebreak', () => {
@@ -5,7 +5,7 @@ import { MarkdownParser } from '../../../markdown';
5
5
  import { eval } from '../../combinator/data/parser';
6
6
  import { header } from '../header';
7
7
  import { block } from '../block';
8
- import { segment, SEGMENT_LENGTH_LIMIT } from '../segment';
8
+ import { segment, validate, MAX_SEGMENT_SIZE } from '../segment';
9
9
  import { normalize } from './normalize';
10
10
  import { headers } from './header';
11
11
  import { figure } from '../function/figure';
@@ -22,7 +22,7 @@ const inherit = memoize<MarkdownParser.Context, MarkdownParser.Context>(context
22
22
  const inherit2 = memoize<MarkdownParser.Context, (url: string) => MarkdownParser.Context>(context => memoize((_: string) => ObjectCreate(context)), new WeakMap());
23
23
 
24
24
  export function parse(source: string, opts: Options = {}, context?: MarkdownParser.Context): DocumentFragment {
25
- if (source.length > SEGMENT_LENGTH_LIMIT) throw new Error(`Too large input over ${SEGMENT_LENGTH_LIMIT.toLocaleString('en')} in length.`);
25
+ if (!validate(source, MAX_SEGMENT_SIZE)) throw new Error(`Too large input over ${MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.`);
26
26
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
27
27
  source = !context ? normalize(source) : source;
28
28
  assert(!context?.delimiters);
@@ -96,7 +96,7 @@ describe('Unit: parser/block/blockquote', () => {
96
96
  assert.deepStrictEqual(inspect(parser('!>> ## a\n> ## a')), [['<blockquote><blockquote><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><h2>a</h2><ol class="annotations"></ol><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><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
98
98
  assert.deepStrictEqual(inspect(parser('!>> ~~~figure $fig-a\n>> > \n>>\n~~~\n> ~~~figure $fig-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1: </span><figcaption><a class="index">a</a></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
99
- assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><ol class="references"></ol></section></blockquote>'], '']);
99
+ assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><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-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><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><ol class="annotations"></ol><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><ol class="annotations"></ol><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"><a>*1</a></sup><sup class="reference disabled" title="b"><a>[1]</a></sup></p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><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"><a>*1</a></sup><sup class="reference disabled" title="b"><a>[1]</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"><li>b<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><ol class="annotations"></ol><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">'], '']);
@@ -26,7 +26,7 @@ export const segment: FigParser.SegmentParser = block(validate(['[$', '$'],
26
26
 
27
27
  export const fig: FigParser = block(rewrite(segment, convert(
28
28
  source => {
29
- const fence = (/^[^\n]*\n!?>+\s/.test(source) && source.match(/^~{3,}(?=\s*$)/gm) || [])
29
+ const fence = (/^[^\n]*\n!?>+\s/.test(source) && source.match(/^~{3,}(?=\s*$)/mg) || [])
30
30
  .reduce((max, fence) => fence > max ? fence : max, '~~') + '~';
31
31
  return `${fence}figure ${source}\n\n${fence}`;
32
32
  },
@@ -82,7 +82,7 @@ const head: CellParser.HeadParser = creator(block(fmap(open(
82
82
  anyline,
83
83
  some(contentline, delimiter),
84
84
  ]),
85
- visualize(trim(some(union([inline]))), '')),
85
+ visualize(trim(some(union([inline]))))),
86
86
  true),
87
87
  ns => [html('th', attributes(ns.shift()! as string), defrag(ns))]),
88
88
  false));
@@ -94,7 +94,7 @@ const data: CellParser.DataParser = creator(block(fmap(open(
94
94
  anyline,
95
95
  some(contentline, delimiter),
96
96
  ]),
97
- visualize(trim(some(union([inline]))), '')),
97
+ visualize(trim(some(union([inline]))))),
98
98
  true),
99
99
  ns => [html('td', attributes(ns.shift()! as string), defrag(ns))]),
100
100
  false));
@@ -64,24 +64,22 @@ describe('Unit: parser/block/heading', () => {
64
64
  assert.deepStrictEqual(inspect(parser('# a [#b]')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
65
65
  assert.deepStrictEqual(inspect(parser('# a [#b] ')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
66
66
  assert.deepStrictEqual(inspect(parser('# a [#b]\\')), [['<h1 id="index:a_[#b]">a [#b]</h1>'], '']);
67
+ assert.deepStrictEqual(inspect(parser('# a [#B]')), [['<h1 id="index:B">a<span class="indexer" data-index="B"></span></h1>'], '']);
68
+ assert.deepStrictEqual(inspect(parser('# a [#b ]')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
69
+ assert.deepStrictEqual(inspect(parser('# a [#b ]')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
67
70
  assert.deepStrictEqual(inspect(parser('# a [#b c]')), [['<h1 id="index:b_c">a<span class="indexer" data-index="b_c"></span></h1>'], '']);
68
71
  assert.deepStrictEqual(inspect(parser('# a [#*b*`c`${d}$]')), [['<h1 id="index:b`c`${d}$">a<span class="indexer" data-index="b`c`${d}$"></span></h1>'], '']);
72
+ assert.deepStrictEqual(inspect(parser('# a [#@a]')), [['<h1 id="index:@a">a<span class="indexer" data-index="@a"></span></h1>'], '']);
73
+ assert.deepStrictEqual(inspect(parser('# a [#http://host]')), [['<h1 id="index:http://host">a<span class="indexer" data-index="http://host"></span></h1>'], '']);
74
+ assert.deepStrictEqual(inspect(parser('# a [#!http://host]')), [['<h1 id="index:!http://host">a<span class="indexer" data-index="!http://host"></span></h1>'], '']);
75
+ assert.deepStrictEqual(inspect(parser('# a [#a((b))]')), [['<h1 id="index:a((b))">a<span class="indexer" data-index="a((b))"></span></h1>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('# a [#a[[b]]]')), [['<h1 id="index:a[[b]]">a<span class="indexer" data-index="a[[b]]"></span></h1>'], '']);
77
+ assert.deepStrictEqual(inspect(parser('# a [#b|#c]')), [['<h1 id="index:c">a<span class="indexer" data-index="c"></span></h1>'], '']);
69
78
  assert.deepStrictEqual(inspect(parser('# a [#b] [#c]')), [['<h1 id="index:c">a [#b]<span class="indexer" data-index="c"></span></h1>'], '']);
70
79
  assert.deepStrictEqual(inspect(parser('# a [#b] \n')), [['<h1 id="index:b">a<span class="indexer" data-index="b"></span></h1>'], '']);
71
80
  assert.deepStrictEqual(inspect(parser('# a \\[#b]')), [['<h1 id="index:a_[#b]">a [#b]</h1>'], '']);
72
- assert.deepStrictEqual(inspect(parser('# A')), [['<h1 id="index:A">A</h1>'], '']);
73
- assert.deepStrictEqual(inspect(parser('# *A*')), [['<h1 id="index:A"><em>A</em></h1>'], '']);
74
- assert.deepStrictEqual(inspect(parser('# `A`')), [['<h1 id="index:`A`"><code data-src="`A`">A</code></h1>'], '']);
75
- assert.deepStrictEqual(inspect(parser('# ${A}$')), [['<h1 id="index:${A}$"><span class="math" translate="no" data-src="${A}$">${A}$</span></h1>'], '']);
76
- assert.deepStrictEqual(inspect(parser('# A [#B]')), [['<h1 id="index:B">A<span class="indexer" data-index="B"></span></h1>'], '']);
77
- assert.deepStrictEqual(inspect(parser('# A [#`B`]')), [['<h1 id="index:`B`">A<span class="indexer" data-index="`B`"></span></h1>'], '']);
78
- assert.deepStrictEqual(inspect(parser('# A [#@a]')), [['<h1 id="index:@a">A<span class="indexer" data-index="@a"></span></h1>'], '']);
79
- assert.deepStrictEqual(inspect(parser('# A [#http://host]')), [['<h1 id="index:http://host">A<span class="indexer" data-index="http://host"></span></h1>'], '']);
80
- assert.deepStrictEqual(inspect(parser('# A [#!http://host]')), [['<h1 id="index:!http://host">A<span class="indexer" data-index="!http://host"></span></h1>'], '']);
81
- assert.deepStrictEqual(inspect(parser('# A [#a((b))]')), [['<h1 id="index:a((b))">A<span class="indexer" data-index="a((b))"></span></h1>'], '']);
82
- assert.deepStrictEqual(inspect(parser('# A [#a[[b]]]')), [['<h1 id="index:a[[b]]">A<span class="indexer" data-index="a[[b]]"></span></h1>'], '']);
83
- assert.deepStrictEqual(inspect(parser('# A [#b|#c]')), [['<h1 id="index:c">A<span class="indexer" data-index="c"></span></h1>'], '']);
84
81
  assert.deepStrictEqual(inspect(parser('## a [#b] [#c]')), [['<h2 id="index:c">a [<a href="/hashtags/b" class="hashtag">#b</a>]<span class="indexer" data-index="c"></span></h2>'], '']);
82
+ assert.deepStrictEqual(inspect(parser('## a [#b ] [#c ]')), [['<h2 id="index:c">a [<a href="/hashtags/b" class="hashtag">#b</a> ]<span class="indexer" data-index="c"></span></h2>'], '']);
85
83
  });
86
84
 
87
85
  });
@@ -16,7 +16,14 @@ export const ilist: IListParser = lazy(() => block(fmap(validate(
16
16
  ]),
17
17
  ns => [html('li', defrag(fillFirstLine(ns)))]),
18
18
  ]))))),
19
- es => [html('ul', { class: 'invalid', 'data-invalid-syntax': 'list', 'data-invalid-type': 'syntax', 'data-invalid-description': 'Use "-" instead of "+" or "*".' }, es)])));
19
+ es => [
20
+ html('ul', {
21
+ class: 'invalid',
22
+ 'data-invalid-syntax': 'list',
23
+ 'data-invalid-type': 'syntax',
24
+ 'data-invalid-description': 'Use "-" instead of "+" or "*".',
25
+ }, es),
26
+ ])));
20
27
 
21
28
  export const ilist_: IListParser = convert(
22
29
  source => source.replace(/^[-+*](?=$|\n)/, `$& `),
@@ -20,6 +20,11 @@ describe('Unit: parser/block/paragraph', () => {
20
20
  assert.deepStrictEqual(inspect(parser('a\\ \n')), [['<p>a</p>'], '']);
21
21
  assert.deepStrictEqual(inspect(parser('a\\\n')), [['<p>a</p>'], '']);
22
22
  assert.deepStrictEqual(inspect(parser('a\\\nb')), [['<p>a<span class="linebreak"> </span>b</p>'], '']);
23
+ assert.deepStrictEqual(inspect(parser('<wbr>')), [['<p>&lt;wbr&gt;</p>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('<wbr>\n')), [['<p>&lt;wbr&gt;</p>'], '']);
25
+ assert.deepStrictEqual(inspect(parser('<wbr>\na')), [['<p>&lt;wbr&gt;<br>a</p>'], '']);
26
+ assert.deepStrictEqual(inspect(parser('a\n<wbr>\n')), [['<p>a<br>&lt;wbr&gt;</p>'], '']);
27
+ assert.deepStrictEqual(inspect(parser('a\n<wbr>\nb')), [['<p>a<br>&lt;wbr&gt;<br>b</p>'], '']);
23
28
  assert.deepStrictEqual(inspect(parser(' a')), [['<p>a</p>'], '']);
24
29
  });
25
30
 
@@ -52,6 +57,8 @@ describe('Unit: parser/block/paragraph', () => {
52
57
  it('comment', () => {
53
58
  assert.deepStrictEqual(inspect(parser('[# a #]')), [['<p>[# a #]</p>'], '']);
54
59
  assert.deepStrictEqual(inspect(parser('[# a #]b')), [['<p><sup class="comment" title="a"></sup>b</p>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('[#\n<wbr>\n#]')), [['<p>[#<br>&lt;wbr&gt;<br>#]</p>'], '']);
61
+ assert.deepStrictEqual(inspect(parser('[#\n<wbr>\n#]a')), [['<p><sup class="comment" title="<wbr>"></sup>a</p>'], '']);
55
62
  });
56
63
 
57
64
  });
@@ -37,7 +37,7 @@ describe('Unit: parser/footnote', () => {
37
37
  html('ol', [
38
38
  html('li', { id: 'annotation:def:1' }, [
39
39
  'a b',
40
- html('sup', [html('a', { href: '#annotation:ref:1' }, '~1')])
40
+ html('sup', [html('a', { href: '#annotation:ref:1' }, '^1')])
41
41
  ]),
42
42
  ]).outerHTML);
43
43
  }
@@ -65,11 +65,11 @@ describe('Unit: parser/footnote', () => {
65
65
  html('ol', [
66
66
  html('li', { id: 'annotation:def:1' }, [
67
67
  '1',
68
- html('sup', [html('a', { href: '#annotation:ref:1' }, '~1')])
68
+ html('sup', [html('a', { href: '#annotation:ref:1' }, '^1')])
69
69
  ]),
70
70
  html('li', { id: 'annotation:def:2' }, [
71
71
  '12345678901234567890',
72
- html('sup', [html('a', { href: '#annotation:ref:2' }, '~2')])
72
+ html('sup', [html('a', { href: '#annotation:ref:2' }, '^2')])
73
73
  ]),
74
74
  ]).outerHTML);
75
75
  }
@@ -106,22 +106,22 @@ describe('Unit: parser/footnote', () => {
106
106
  html('ol', [
107
107
  html('li', { id: 'annotation:def:1' }, [
108
108
  '1',
109
- html('sup', [html('a', { href: '#annotation:ref:1' }, '~1')])
109
+ html('sup', [html('a', { href: '#annotation:ref:1' }, '^1')])
110
110
  ]),
111
111
  html('li', { id: 'annotation:def:2' }, [
112
112
  '2',
113
113
  html('sup', [
114
- html('a', { href: '#annotation:ref:2' }, '~2'),
115
- html('a', { href: '#annotation:ref:4' }, '~4'),
114
+ html('a', { href: '#annotation:ref:2' }, '^2'),
115
+ html('a', { href: '#annotation:ref:4' }, '^4'),
116
116
  ]),
117
117
  ]),
118
118
  html('li', { id: 'annotation:def:3' }, [
119
119
  '3',
120
- html('sup', [html('a', { href: '#annotation:ref:3' }, '~3')])
120
+ html('sup', [html('a', { href: '#annotation:ref:3' }, '^3')])
121
121
  ]),
122
122
  html('li', { id: 'annotation:def:4' }, [
123
123
  '4',
124
- html('sup', [html('a', { href: '#annotation:ref:5' }, '~5')])
124
+ html('sup', [html('a', { href: '#annotation:ref:5' }, '^5')])
125
125
  ]),
126
126
  ]).outerHTML);
127
127
  }
@@ -143,13 +143,13 @@ describe('Unit: parser/footnote', () => {
143
143
  assert.deepStrictEqual(
144
144
  [...target.children].map(el => el.outerHTML),
145
145
  [
146
- '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup><br>~~~</p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><ol class="references"></ol></section></blockquote>',
147
- '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>~1</a></sup></li></ol><ol class="references"></ol></section></aside>',
146
+ '<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup><br>~~~</p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>',
147
+ '<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></aside>',
148
148
  '<p><sup class="annotation" id="annotation:ref:1" title="a"><a href="#annotation:def:1">*1</a></sup></p>',
149
149
  ]);
150
150
  assert.deepStrictEqual(
151
151
  footnote.outerHTML,
152
- '<ol><li id="annotation:def:1">a<sup><a href="#annotation:ref:1">~1</a></sup></li></ol>');
152
+ '<ol><li id="annotation:def:1">a<sup><a href="#annotation:ref:1">^1</a></sup></li></ol>');
153
153
  }
154
154
  });
155
155
 
@@ -172,7 +172,7 @@ describe('Unit: parser/footnote', () => {
172
172
  html('ol', [
173
173
  html('li', { id: 'annotation:0:def:1' }, [
174
174
  'a b',
175
- html('sup', [html('a', { href: '#annotation:0:ref:1' }, '~1')])
175
+ html('sup', [html('a', { href: '#annotation:0:ref:1' }, '^1')])
176
176
  ]),
177
177
  ]).outerHTML);
178
178
  }
@@ -200,7 +200,7 @@ describe('Unit: parser/footnote', () => {
200
200
  html('ol', [
201
201
  html('li', { id: 'reference:def:1' }, [
202
202
  'a b',
203
- html('sup', [html('a', { href: '#reference:ref:1' }, '~1')])
203
+ html('sup', [html('a', { href: '#reference:ref:1' }, '^1')])
204
204
  ]),
205
205
  ]).outerHTML);
206
206
  }
@@ -232,9 +232,9 @@ describe('Unit: parser/footnote', () => {
232
232
  html('li', { id: 'reference:def:1' }, [
233
233
  'b',
234
234
  html('sup', [
235
- html('a', { href: '#reference:ref:1' }, '~1'),
236
- html('a', { href: '#reference:ref:2', title: 'b' }, '~2'),
237
- html('a', { href: '#reference:ref:3' }, '~3'),
235
+ html('a', { href: '#reference:ref:1' }, '^1'),
236
+ html('a', { href: '#reference:ref:2', title: 'b' }, '^2'),
237
+ html('a', { href: '#reference:ref:3' }, '^3'),
238
238
  ])
239
239
  ]),
240
240
  ]).outerHTML);
@@ -109,7 +109,7 @@ function build(
109
109
  ? title
110
110
  : undefined,
111
111
  },
112
- `~${refIndex}`));
112
+ `^${refIndex}`));
113
113
  }
114
114
  if (!footnote) return;
115
115
  const { children } = footnote;
@@ -20,7 +20,6 @@ describe('Unit: parser/inline/annotation', () => {
20
20
  assert.deepStrictEqual(inspect(parser('((\na))')), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('((\\ a))')), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('((\\\na))')), undefined);
23
- assert.deepStrictEqual(inspect(parser('((a ))')), undefined);
24
23
  assert.deepStrictEqual(inspect(parser('((a\n))')), undefined);
25
24
  assert.deepStrictEqual(inspect(parser('((a\\\n))')), undefined);
26
25
  assert.deepStrictEqual(inspect(parser('((a\nb))')), undefined);
@@ -36,7 +35,11 @@ describe('Unit: parser/inline/annotation', () => {
36
35
 
37
36
  it('basic', () => {
38
37
  assert.deepStrictEqual(inspect(parser('((a))')), [['<sup class="annotation">a</sup>'], '']);
39
- assert.deepStrictEqual(inspect(parser('((a ))')), [['<sup class="annotation">a </sup>'], '']);
38
+ assert.deepStrictEqual(inspect(parser('((a ))')), [['<sup class="annotation">a</sup>'], '']);
39
+ assert.deepStrictEqual(inspect(parser('((a ))')), [['<sup class="annotation">a</sup>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('((a &nbsp;))')), [['<sup class="annotation">a</sup>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('((a <wbr>))')), [['<sup class="annotation">a</sup>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('((a [# b #]))')), [['<sup class="annotation">a <sup class="comment" title="b"></sup></sup>'], '']);
40
43
  assert.deepStrictEqual(inspect(parser('((ab))')), [['<sup class="annotation">ab</sup>'], '']);
41
44
  });
42
45
 
@@ -1,11 +1,11 @@
1
1
  import { undefined } from 'spica/global';
2
2
  import { AnnotationParser } from '../inline';
3
- import { union, some, validate, verify, guard, context, creator, surround, lazy, fmap } from '../../combinator';
3
+ import { union, some, validate, guard, context, creator, surround, lazy, fmap } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { startTight, isEndTight } from '../util';
5
+ import { startTight, trimEnd } from '../util';
6
6
  import { html, defrag } from 'typed-dom';
7
7
 
8
- export const annotation: AnnotationParser = lazy(() => creator(validate('((', '))', '\n', fmap(verify(surround(
8
+ export const annotation: AnnotationParser = lazy(() => creator(validate('((', '))', '\n', fmap(surround(
9
9
  '((',
10
10
  guard(context => context.syntax?.inline?.annotation ?? true,
11
11
  startTight(
@@ -21,5 +21,4 @@ export const annotation: AnnotationParser = lazy(() => creator(validate('((', ')
21
21
  }}, state: undefined },
22
22
  union([some(inline, ')', /^\\?\n/)])))),
23
23
  '))'),
24
- isEndTight),
25
- ns => [html('sup', { class: 'annotation' }, defrag(ns))]))));
24
+ ns => [html('sup', { class: 'annotation' }, trimEnd(defrag(ns)))]))));
@@ -6,5 +6,5 @@ export const comment: CommentParser = creator(validate('[#', '#]', match(
6
6
  /^\[(#+)\s+((?:\S+\s+)+?)(\1\]|$)/,
7
7
  ([, , title, closer]) => (rest, { resources }) =>
8
8
  closer
9
- ? [[html('sup', { class: 'comment', title: title.trim() })], rest]
9
+ ? [[html('sup', { class: 'comment', title: title.trim().replace(/\x7F.?/gs, '') })], rest]
10
10
  : resources && void (resources.budget -= title.match(/\s+/g)!.length))));
@@ -27,6 +27,7 @@ describe('Unit: parser/inline/deletion', () => {
27
27
  assert.deepStrictEqual(inspect(parser('~~\\\na~~')), [['<del><span class="linebreak"> </span>a</del>'], '']);
28
28
  assert.deepStrictEqual(inspect(parser('~~<wbr>a~~')), [['<del><wbr>a</del>'], '']);
29
29
  assert.deepStrictEqual(inspect(parser('~~[# a #]b~~')), [['<del><sup class="comment" title="a"></sup>b</del>'], '']);
30
+ assert.deepStrictEqual(inspect(parser('~~a\n~~')), [['<del>a</del>'], '']);
30
31
  assert.deepStrictEqual(inspect(parser('~~a\nb~~')), [['<del>a<br>b</del>'], '']);
31
32
  assert.deepStrictEqual(inspect(parser('~~a\\\nb~~')), [['<del>a<span class="linebreak"> </span>b</del>'], '']);
32
33
  assert.deepStrictEqual(inspect(parser('~~\\~~~')), [['<del>~</del>'], '']);
@@ -2,6 +2,7 @@ import { DeletionParser } from '../inline';
2
2
  import { union, some, creator, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
+ import { trimEndBR } from '../util';
5
6
  import { html, defrag } from 'typed-dom';
6
7
  import { unshift } from 'spica/array';
7
8
 
@@ -9,5 +10,5 @@ export const deletion: DeletionParser = lazy(() => creator(surround(
9
10
  str('~~'),
10
11
  union([some(inline, '~~')]),
11
12
  str('~~'), false,
12
- ([, bs], rest) => [[html('del', defrag(bs))], rest],
13
+ ([, bs], rest) => [[html('del', defrag(trimEndBR(bs)))], rest],
13
14
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -1,18 +1,18 @@
1
1
  import { EmphasisParser } from '../inline';
2
- import { union, some, creator, surround, lazy } from '../../combinator';
2
+ import { union, 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';
6
- import { startTight, isEndTight, trimEndBR } from '../util';
6
+ import { startTight, verifyEndTight, trimEndBR } from '../util';
7
7
  import { html, defrag } from 'typed-dom';
8
8
  import { unshift } from 'spica/array';
9
9
 
10
- export const emphasis: EmphasisParser = lazy(() => creator(surround(
11
- str('*', '*'),
10
+ export const emphasis: EmphasisParser = lazy(() => creator(surround(close(
11
+ str('*'), /^(?!\*)/),
12
12
  startTight(some(union([strong, some(inline, '*')]))),
13
13
  str('*'), false,
14
14
  ([as, bs, cs], rest) =>
15
- isEndTight(bs)
15
+ verifyEndTight(bs)
16
16
  ? [[html('em', defrag(trimEndBR(bs)))], rest]
17
17
  : [unshift(as, bs), cs[0] + rest],
18
18
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -2,7 +2,7 @@ import { EmStrongParser } from '../inline';
2
2
  import { union, some, creator, surround, lazy, bind } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { startTight, isEndTight, trimEndBR } from '../util';
5
+ import { startTight, verifyEndTight, trimEndBR } from '../util';
6
6
  import { html, defrag } from 'typed-dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
@@ -11,13 +11,13 @@ export const emstrong: EmStrongParser = lazy(() => creator(surround(
11
11
  startTight(union([some(inline, '*')])),
12
12
  str(/^\*{1,3}/), false,
13
13
  ([as, bs, cs], rest, context) => {
14
- if (!isEndTight(bs)) return [unshift(as, bs), cs[0] + rest];
14
+ if (!verifyEndTight(bs)) return [unshift(as, bs), cs[0] + rest];
15
15
  switch (cs[0]) {
16
16
  case '*':
17
17
  return bind<EmStrongParser>(
18
18
  union([some(inline, '**')]),
19
19
  (ds, rest) =>
20
- rest.slice(0, 2) === '**' && isEndTight(ds)
20
+ rest.slice(0, 2) === '**' && verifyEndTight(ds)
21
21
  ? [[html('strong', unshift([html('em', defrag(trimEndBR(bs)))], defrag(trimEndBR(ds))))], rest.slice(2)]
22
22
  : [unshift(['**', html('em', defrag(trimEndBR(bs)))], ds), rest])
23
23
  (rest, context) ?? [['**', html('em', defrag(trimEndBR(bs)))], rest];
@@ -25,7 +25,7 @@ export const emstrong: EmStrongParser = lazy(() => creator(surround(
25
25
  return bind<EmStrongParser>(
26
26
  union([some(inline, '*')]),
27
27
  (ds, rest) =>
28
- rest.slice(0, 1) === '*' && isEndTight(ds)
28
+ rest.slice(0, 1) === '*' && verifyEndTight(ds)
29
29
  ? [[html('em', unshift([html('strong', defrag(trimEndBR(bs)))], defrag(trimEndBR(ds))))], rest.slice(1)]
30
30
  : [unshift(['*', html('strong', defrag(trimEndBR(bs)))], ds), rest])
31
31
  (rest, context) ?? [['*', html('strong', defrag(trimEndBR(bs)))], rest];