securemark 0.292.0 → 0.293.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 (119) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +395 -287
  3. package/markdown.d.ts +22 -39
  4. package/package.json +1 -1
  5. package/src/combinator/control/constraint/contract.ts +6 -15
  6. package/src/combinator/control/manipulation/clear.ts +3 -4
  7. package/src/combinator/control/manipulation/fence.ts +3 -1
  8. package/src/combinator/control/manipulation/indent.ts +5 -11
  9. package/src/combinator/control/manipulation/match.ts +3 -2
  10. package/src/combinator/control/manipulation/recovery.ts +1 -1
  11. package/src/combinator/control/manipulation/scope.ts +3 -10
  12. package/src/combinator/control/manipulation/surround.ts +4 -24
  13. package/src/combinator/data/parser/context/delimiter.ts +10 -9
  14. package/src/combinator/data/parser/context.ts +31 -0
  15. package/src/combinator/data/parser/inits.ts +1 -1
  16. package/src/combinator/data/parser/sequence.ts +1 -1
  17. package/src/combinator/data/parser/some.test.ts +1 -1
  18. package/src/combinator/data/parser/some.ts +4 -5
  19. package/src/combinator/data/parser.ts +0 -1
  20. package/src/parser/api/parse.test.ts +16 -8
  21. package/src/parser/api/parse.ts +1 -2
  22. package/src/parser/autolink.test.ts +7 -7
  23. package/src/parser/autolink.ts +2 -4
  24. package/src/parser/block/blockquote.test.ts +1 -1
  25. package/src/parser/block/blockquote.ts +6 -6
  26. package/src/parser/block/codeblock.ts +1 -1
  27. package/src/parser/block/dlist.test.ts +1 -1
  28. package/src/parser/block/dlist.ts +6 -6
  29. package/src/parser/block/extension/aside.ts +1 -1
  30. package/src/parser/block/extension/example.ts +1 -1
  31. package/src/parser/block/extension/fig.ts +3 -3
  32. package/src/parser/block/extension/figbase.ts +1 -1
  33. package/src/parser/block/extension/figure.ts +4 -4
  34. package/src/parser/block/extension/message.ts +1 -1
  35. package/src/parser/block/extension/placeholder.ts +1 -1
  36. package/src/parser/block/extension/table.test.ts +1 -1
  37. package/src/parser/block/extension/table.ts +15 -15
  38. package/src/parser/block/extension.ts +2 -2
  39. package/src/parser/block/heading.test.ts +1 -1
  40. package/src/parser/block/heading.ts +2 -2
  41. package/src/parser/block/ilist.test.ts +3 -3
  42. package/src/parser/block/ilist.ts +4 -4
  43. package/src/parser/block/mathblock.ts +1 -1
  44. package/src/parser/block/mediablock.ts +1 -1
  45. package/src/parser/block/olist.test.ts +16 -14
  46. package/src/parser/block/olist.ts +12 -12
  47. package/src/parser/block/pagebreak.ts +1 -1
  48. package/src/parser/block/paragraph.test.ts +2 -2
  49. package/src/parser/block/paragraph.ts +2 -2
  50. package/src/parser/block/reply/cite.ts +4 -4
  51. package/src/parser/block/reply/quote.ts +5 -4
  52. package/src/parser/block/reply.ts +3 -3
  53. package/src/parser/block/sidefence.ts +3 -3
  54. package/src/parser/block/table.ts +10 -10
  55. package/src/parser/block/ulist.test.ts +8 -7
  56. package/src/parser/block/ulist.ts +6 -6
  57. package/src/parser/block.ts +48 -15
  58. package/src/parser/header.ts +3 -3
  59. package/src/parser/inline/autolink/account.test.ts +8 -7
  60. package/src/parser/inline/autolink/account.ts +11 -8
  61. package/src/parser/inline/autolink/anchor.test.ts +1 -1
  62. package/src/parser/inline/autolink/anchor.ts +21 -17
  63. package/src/parser/inline/autolink/channel.test.ts +8 -8
  64. package/src/parser/inline/autolink/channel.ts +40 -15
  65. package/src/parser/inline/autolink/email.test.ts +15 -15
  66. package/src/parser/inline/autolink/email.ts +5 -7
  67. package/src/parser/inline/autolink/hashnum.test.ts +4 -9
  68. package/src/parser/inline/autolink/hashnum.ts +8 -4
  69. package/src/parser/inline/autolink/hashtag.test.ts +9 -10
  70. package/src/parser/inline/autolink/hashtag.ts +9 -6
  71. package/src/parser/inline/autolink/url.test.ts +72 -74
  72. package/src/parser/inline/autolink/url.ts +19 -23
  73. package/src/parser/inline/autolink.ts +21 -24
  74. package/src/parser/inline/bracket.ts +3 -3
  75. package/src/parser/inline/code.ts +2 -2
  76. package/src/parser/inline/deletion.test.ts +2 -2
  77. package/src/parser/inline/deletion.ts +1 -1
  78. package/src/parser/inline/emphasis.test.ts +5 -5
  79. package/src/parser/inline/emphasis.ts +2 -7
  80. package/src/parser/inline/emstrong.test.ts +14 -14
  81. package/src/parser/inline/emstrong.ts +4 -16
  82. package/src/parser/inline/extension/index.test.ts +5 -3
  83. package/src/parser/inline/extension/index.ts +4 -7
  84. package/src/parser/inline/extension/indexer.test.ts +1 -1
  85. package/src/parser/inline/extension/indexer.ts +3 -3
  86. package/src/parser/inline/extension/label.ts +1 -1
  87. package/src/parser/inline/extension/placeholder.ts +1 -1
  88. package/src/parser/inline/html.test.ts +2 -2
  89. package/src/parser/inline/html.ts +14 -14
  90. package/src/parser/inline/htmlentity.ts +1 -1
  91. package/src/parser/inline/insertion.test.ts +2 -2
  92. package/src/parser/inline/insertion.ts +1 -1
  93. package/src/parser/inline/italic.test.ts +5 -5
  94. package/src/parser/inline/italic.ts +1 -1
  95. package/src/parser/inline/link.ts +15 -15
  96. package/src/parser/inline/mark.test.ts +5 -5
  97. package/src/parser/inline/mark.ts +1 -1
  98. package/src/parser/inline/math.test.ts +6 -6
  99. package/src/parser/inline/math.ts +7 -11
  100. package/src/parser/inline/media.ts +9 -9
  101. package/src/parser/inline/reference.test.ts +4 -4
  102. package/src/parser/inline/reference.ts +4 -4
  103. package/src/parser/inline/remark.test.ts +7 -7
  104. package/src/parser/inline/remark.ts +2 -2
  105. package/src/parser/inline/ruby.ts +3 -1
  106. package/src/parser/inline/shortmedia.ts +6 -9
  107. package/src/parser/inline/strong.test.ts +5 -5
  108. package/src/parser/inline/strong.ts +2 -7
  109. package/src/parser/inline.test.ts +13 -11
  110. package/src/parser/source/escapable.test.ts +6 -6
  111. package/src/parser/source/escapable.ts +29 -5
  112. package/src/parser/source/line.ts +28 -4
  113. package/src/parser/source/str.ts +5 -27
  114. package/src/parser/source/text.test.ts +27 -27
  115. package/src/parser/source/text.ts +58 -6
  116. package/src/parser/source/unescapable.test.ts +6 -6
  117. package/src/parser/source/unescapable.ts +27 -3
  118. package/src/parser/util.ts +3 -3
  119. package/src/parser/visibility.ts +14 -9
@@ -3,16 +3,17 @@ import { union, some, block, validate, rewrite, convert, lazy, fmap } from '../.
3
3
  import { math } from '../../inline/math';
4
4
  import { autolink } from '../../inline/autolink';
5
5
  import { linebreak, unescsource, anyline } from '../../source';
6
+ import { linearize } from '../../util';
6
7
  import { html, defrag } from 'typed-dom/dom';
7
8
 
8
- export const syntax = /^>+[^\S\n]/;
9
+ export const syntax = />+[^\S\n]/y;
9
10
 
10
11
  export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(validate(
11
12
  '>',
12
13
  rewrite(
13
14
  some(validate(syntax, anyline)),
14
- convert(
15
- source => source.replace(/(?<=^>+[^\S\n])/mg, '\r').replace(/\n$/, ''),
15
+ linearize(convert(
16
+ source => source.replace(/(?<=^>+[^\S\n])/mg, '\r'),
16
17
  some(union([
17
18
  // quote補助関数が残した数式をパースする。
18
19
  math,
@@ -20,7 +21,7 @@ export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(validate(
20
21
  linebreak,
21
22
  unescsource,
22
23
  ])),
23
- false))),
24
+ false), -1))),
24
25
  (ns: [string, ...(string | HTMLElement)[]]) => [
25
26
  html('span', { class: 'quote' }, defrag(ns)),
26
27
  html('br'),
@@ -4,11 +4,11 @@ import { cite, syntax as csyntax } from './reply/cite';
4
4
  import { quote, syntax as qsyntax } from './reply/quote';
5
5
  import { inline } from '../inline';
6
6
  import { anyline } from '../source';
7
- import { lineable } from '../util';
7
+ import { linearize } from '../util';
8
8
  import { visualize, trimBlankNodeEnd } from '../visibility';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
- const delimiter = new RegExp(`${csyntax.source}|${qsyntax.source}`);
11
+ const delimiter = new RegExp(`${csyntax.source}|${qsyntax.source}`, 'y');
12
12
 
13
13
  export const reply: ReplyParser = block(validate(csyntax, fmap(
14
14
  some(union([
@@ -16,6 +16,6 @@ export const reply: ReplyParser = block(validate(csyntax, fmap(
16
16
  quote,
17
17
  rewrite(
18
18
  some(anyline, delimiter),
19
- visualize(lineable(some(inline), 1))),
19
+ visualize(linearize(some(inline), 1))),
20
20
  ])),
21
21
  ns => [html('p', trimBlankNodeEnd(defrag(ns)))])));
@@ -7,7 +7,7 @@ import { invalid } from '../util';
7
7
  import { html, define, defrag } from 'typed-dom/dom';
8
8
 
9
9
  export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
10
- /^(?=\|+(?:[^\S\n]|\n\|))(?:\|+(?:[^\S\n][^\n]*)?(?:$|\n))+$/,
10
+ /(?=\|+(?:[^\S\n]|\n\|))(?:\|+(?:[^\S\n][^\n]*)?(?:$|\n))+$/y,
11
11
  union([source]), false),
12
12
  ([el]) => [
13
13
  define(el, {
@@ -16,13 +16,13 @@ export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
16
16
  }),
17
17
  ])));
18
18
 
19
- const opener = /^(?=\|\|+(?:$|\s))/;
19
+ const opener = /(?=\|\|+(?:$|\s))/y;
20
20
  const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
21
21
 
22
22
  const source: SidefenceParser.SourceParser = lazy(() => fmap(
23
23
  some(recursion(Recursion.block, union([
24
24
  focus(
25
- /^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/,
25
+ /(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/y,
26
26
  convert(unindent, source, false, true), false),
27
27
  rewrite(
28
28
  some(contentline, opener),
@@ -13,7 +13,7 @@ import AlignParser = TableParser.AlignParser;
13
13
  import CellParser = TableParser.CellParser;
14
14
 
15
15
  export const table: TableParser = lazy(() => block(fmap(validate(
16
- /^\|[^\n]*(?:\n\|[^\n]*){2}/,
16
+ /\|[^\n]*(?:\n\|[^\n]*){2}/y,
17
17
  sequence([
18
18
  row(some(head), true),
19
19
  row(some(align), false),
@@ -27,7 +27,7 @@ export const table: TableParser = lazy(() => block(fmap(validate(
27
27
  ])));
28
28
 
29
29
  const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean): RowParser<P> => fallback(fmap(
30
- line(surround(/^(?=\|)/, some(union([parser])), /^[|\\]?\s*$/, optional)),
30
+ line(surround(/(?=\|)/y, some(union([parser])), /[|\\]?\s*$/y, optional)),
31
31
  es => [html('tr', es)]),
32
32
  rewrite(contentline, ({ context: { source } }) => [[
33
33
  html('tr', {
@@ -39,22 +39,22 @@ const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean):
39
39
  const align: AlignParser = fmap(open(
40
40
  '|',
41
41
  union([
42
- focus(/^:-+:?/, ({ context: { source } }) =>
42
+ focus(/:-+:?/y, ({ context: { source } }) =>
43
43
  [[source.at(-1) === ':' ? 'center' : 'start']], false),
44
- focus(/^-+:?/, ({ context: { source } }) =>
44
+ focus(/-+:?/y, ({ context: { source } }) =>
45
45
  [[source.at(-1) === ':' ? 'end' : '']], false),
46
46
  ])),
47
47
  ns => [html('td', defrag(ns))]);
48
48
 
49
49
  const cell: CellParser = surround(
50
- /^\|\s*(?=\S)/,
50
+ /\|\s*(?=\S)/y,
51
51
  trimStart(union([
52
- close(medialink, /^\s*(?=\||$)/),
53
- close(media, /^\s*(?=\||$)/),
54
- close(shortmedia, /^\s*(?=\||$)/),
55
- trimBlank(some(inline, /^\|/, [[/^[|\\]?\s*$/, 9]])),
52
+ close(medialink, /\s*(?=\||$)/y),
53
+ close(media, /\s*(?=\||$)/y),
54
+ close(shortmedia, /\s*(?=\||$)/y),
55
+ trimBlank(some(inline, /\|/y, [[/[|\\]?\s*$/y, 9]])),
56
56
  ])),
57
- /^[^|]*/, true);
57
+ /[^|]*/y, true);
58
58
 
59
59
  const head: CellParser.HeadParser = fmap(
60
60
  cell,
@@ -19,6 +19,7 @@ describe('Unit: parser/block/ulist', () => {
19
19
  assert.deepStrictEqual(inspect(parser('-[ ]'), ctx), undefined);
20
20
  assert.deepStrictEqual(inspect(parser('-[x]'), ctx), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('-\n'), ctx), undefined);
22
+ assert.deepStrictEqual(inspect(parser('-\n- a'), ctx), undefined);
22
23
  assert.deepStrictEqual(inspect(parser(' - '), ctx), undefined);
23
24
  assert.deepStrictEqual(inspect(parser('+'), ctx), undefined);
24
25
  assert.deepStrictEqual(inspect(parser('*'), ctx), undefined);
@@ -36,23 +37,23 @@ describe('Unit: parser/block/ulist', () => {
36
37
 
37
38
  it('multiple', () => {
38
39
  // pending
39
- assert.deepStrictEqual(inspect(parser('-\n-'), ctx), [['<ul><li></li><li></li></ul>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('- \n-'), ctx), [['<ul><li></li><li></li></ul>'], '']);
40
41
  // filled
41
42
  assert.deepStrictEqual(inspect(parser('- 1\n- 2'), ctx), [['<ul><li id="index::1">1</li><li id="index::2">2</li></ul>'], '']);
42
43
  assert.deepStrictEqual(inspect(parser('- 1\n- 2\n- 3'), ctx), [['<ul><li id="index::1">1</li><li id="index::2">2</li><li id="index::3">3</li></ul>'], '']);
43
44
  // invalid
44
- assert.deepStrictEqual(inspect(parser('-\n+'), ctx), [['<ul><li></li><li id="index::+"><span class="invalid">+</span></li></ul>'], '']);
45
- assert.deepStrictEqual(inspect(parser('-\n0'), ctx), [['<ul><li></li><li id="index::0"><span class="invalid">0</span></li></ul>'], '']);
45
+ assert.deepStrictEqual(inspect(parser('- \n+'), ctx), [['<ul><li></li><li id="index::+"><span class="invalid">+</span></li></ul>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('- \n0'), ctx), [['<ul><li></li><li id="index::0"><span class="invalid">0</span></li></ul>'], '']);
46
47
  });
47
48
 
48
49
  it('nest', () => {
49
- assert.deepStrictEqual(inspect(parser('-\n -'), ctx), [['<ul><li><br><ul><li></li></ul></li></ul>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('- \n -'), ctx), [['<ul><li><br><ul><li></li></ul></li></ul>'], '']);
50
51
  assert.deepStrictEqual(inspect(parser('- 1\n - 2'), ctx), [['<ul><li id="index::1">1<ul><li id="index::2">2</li></ul></li></ul>'], '']);
51
52
  assert.deepStrictEqual(inspect(parser('- 1\n - 2\n- 3'), ctx), [['<ul><li id="index::1">1<ul><li id="index::2">2</li></ul></li><li id="index::3">3</li></ul>'], '']);
52
53
  assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3'), ctx), [['<ul><li id="index::1">1<ul><li id="index::2">2</li><li id="index::3">3</li></ul></li></ul>'], '']);
53
54
  assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3'), ctx), [['<ul><li id="index::1">1<ul><li id="index::2">2<ul><li id="index::3">3</li></ul></li></ul></li></ul>'], '']);
54
55
  assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3'), ctx), [['<ul><li id="index::1">1<ul><li id="index::2">2</li></ul></li><li id="index::-_3"><span class="invalid"> - 3</span></li></ul>'], '']);
55
- assert.deepStrictEqual(inspect(parser('-\n -\n +\n -\n +\n+'), ctx), [['<ul><li><br><ul><li></li><li id="index::+"><span class="invalid">+</span></li><li></li><li id="index::+"><span class="invalid">+</span></li></ul></li><li id="index::+"><span class="invalid">+</span></li></ul>'], '']);
56
+ assert.deepStrictEqual(inspect(parser('- \n -\n +\n -\n +\n+'), ctx), [['<ul><li><br><ul><li></li><li id="index::+"><span class="invalid">+</span></li><li></li><li id="index::+"><span class="invalid">+</span></li></ul></li><li id="index::+"><span class="invalid">+</span></li></ul>'], '']);
56
57
  assert.deepStrictEqual(inspect(parser('- 1\n + 2'), ctx), [['<ul><li id="index::1">1<ul class="invalid"><li>2</li></ul></li></ul>'], '']);
57
58
  assert.deepStrictEqual(inspect(parser('- 1\n 0'), ctx), [['<ul><li id="index::1">1<ol><li></li></ol></li></ul>'], '']);
58
59
  assert.deepStrictEqual(inspect(parser('- 1\n 0.'), ctx), [['<ul><li id="index::1">1<ol><li></li></ol></li></ul>'], '']);
@@ -71,10 +72,10 @@ describe('Unit: parser/block/ulist', () => {
71
72
  });
72
73
 
73
74
  it('indexer', () => {
74
- assert.deepStrictEqual(inspect(parser('- [|a]'), ctx), [['<ul><li id="index::[|a]">[|a]</li></ul>'], '']);
75
+ assert.deepStrictEqual(inspect(parser('- [|a]'), ctx), [['<ul><li id="index::[|a]"><span class="invalid">[|a]</span></li></ul>'], '']);
75
76
  assert.deepStrictEqual(inspect(parser('- a [|]'), ctx), [['<ul><li>a<span class="indexer" data-index=""></span></li></ul>'], '']);
76
77
  assert.deepStrictEqual(inspect(parser('- a [|b]'), ctx), [['<ul><li id="index::b">a<span class="indexer" data-index="b"></span></li></ul>'], '']);
77
- assert.deepStrictEqual(inspect(parser('- [ ] [|a]'), ctx), [['<ul class="checklist"><li id="index::[|a]"><span class="checkbox">☐</span>[|a]</li></ul>'], '']);
78
+ assert.deepStrictEqual(inspect(parser('- [ ] [|a]'), ctx), [['<ul class="checklist"><li id="index::[|a]"><span class="checkbox">☐</span><span class="invalid">[|a]</span></li></ul>'], '']);
78
79
  assert.deepStrictEqual(inspect(parser('- [ ] a [|b]'), ctx), [['<ul class="checklist"><li id="index::b"><span class="checkbox">☐</span>a<span class="indexer" data-index="b"></span></li></ul>'], '']);
79
80
  assert.deepStrictEqual(inspect(parser('- a [|]\n - c [|d]'), ctx), [['<ul><li>a<span class="indexer" data-index=""></span><ul><li id="index::d">c<span class="indexer" data-index="d"></span></li></ul></li></ul>'], '']);
80
81
  assert.deepStrictEqual(inspect(parser('- a [|b]\n - c [|d]'), ctx), [['<ul><li id="index::b">a<span class="indexer" data-index="b"></span><ul><li id="index::d">c<span class="indexer" data-index="d"></span></li></ul></li></ul>'], '']);
@@ -4,23 +4,23 @@ import { union, inits, subsequence, some, recursion, block, line, validate, inde
4
4
  import { olist_ } from './olist';
5
5
  import { ilist_, ilistitem } from './ilist';
6
6
  import { inline, indexer, indexee, dataindex } from '../inline';
7
- import { lineable } from '../util';
7
+ import { linearize } from '../util';
8
8
  import { visualize, trimBlank } from '../visibility';
9
9
  import { unshift } from 'spica/array';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const ulist: UListParser = lazy(() => block(validate(
13
- /^-(?=[^\S\n]|\n[^\S\n]*\S)/,
13
+ /- /y,
14
14
  ulist_)));
15
15
 
16
16
  export const ulist_: UListParser = lazy(() => block(fmap(validate(
17
- /^-(?=$|\s)/,
17
+ /-(?=$|[ \n])/y,
18
18
  some(recursion(Recursion.listitem, union([
19
19
  indexee(fmap(fallback(
20
20
  inits([
21
- line(open(/^-(?:$|\s)/, subsequence([
21
+ line(open(/-(?:$|[ \n])/y, subsequence([
22
22
  checkbox,
23
- trim(visualize(lineable(trimBlank(some(union([indexer, inline])))))),
23
+ trim(visualize(linearize(trimBlank(some(union([indexer, inline]))), - 1))),
24
24
  ]), true)),
25
25
  indent(union([ulist_, olist_, ilist_])),
26
26
  ]),
@@ -30,7 +30,7 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
30
30
  es => [format(html('ul', es))])));
31
31
 
32
32
  export const checkbox = focus(
33
- /^\[[xX ]\](?=$|\s)/,
33
+ /\[[xX ]\](?=$|[ \n])/y,
34
34
  ({ context: { source } }) => [[
35
35
  html('span', { class: 'checkbox' }, source[1].trimStart() ? '☑' : '☐'),
36
36
  ]]);
@@ -42,7 +42,7 @@ export const block: BlockParser = reset(
42
42
  {
43
43
  resources: {
44
44
  // バックトラックのせいで文字数制限を受けないようにする。
45
- clock: MAX_SEGMENT_SIZE * 1,
45
+ clock: MAX_SEGMENT_SIZE * 5 + 1,
46
46
  recursions: [
47
47
  10 || Recursion.block,
48
48
  20 || Recursion.blockquote,
@@ -55,23 +55,56 @@ export const block: BlockParser = reset(
55
55
  backtracks: {},
56
56
  },
57
57
  error(union([
58
+ input => {
59
+ const { context: { source, position } } = input;
60
+ if (position === source.length) return;
61
+ switch (source.slice(position, position + 3)) {
62
+ case '===':
63
+ return pagebreak(input);
64
+ case '~~~':
65
+ return extension(input);
66
+ }
67
+ switch (source.slice(position, position + 2)) {
68
+ case '$$':
69
+ return mathblock(input);
70
+ case '[$':
71
+ return extension(input);
72
+ case '[!':
73
+ return mediablock(input);
74
+ case '!>':
75
+ return blockquote(input);
76
+ case '>>':
77
+ return blockquote(input)
78
+ || reply(input);
79
+ case '- ':
80
+ return ulist(input)
81
+ || ilist(input);
82
+ case '+ ':
83
+ case '* ':
84
+ return ilist(input);
85
+ case '~ ':
86
+ return dlist(input);
87
+ }
88
+ switch (source[position]) {
89
+ case '#':
90
+ return heading(input);
91
+ case '|':
92
+ return table(input)
93
+ || sidefence(input);
94
+ case '`':
95
+ return codeblock(input);
96
+ case '$':
97
+ return extension(input);
98
+ case '>':
99
+ return blockquote(input);
100
+ case '!':
101
+ return mediablock(input);
102
+ }
103
+ },
58
104
  emptyline,
59
- pagebreak,
60
- heading,
61
- ulist,
62
105
  olist,
63
- ilist,
64
- dlist,
65
- table,
66
- codeblock,
67
- mathblock,
68
- extension,
69
- sidefence,
70
- blockquote,
71
- mediablock,
72
- reply,
73
106
  paragraph
74
- ])));
107
+ ]) as any));
75
108
 
76
109
  function error(parser: BlockParser): BlockParser {
77
110
  const reg = new RegExp(String.raw`^${Command.Error}.*\n`)
@@ -7,7 +7,7 @@ import { normalize } from './api/normalize';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
9
  export const header: MarkdownParser.HeaderParser = lazy(() => validate(
10
- /^---+[^\S\v\f\r\n]*\r?\n[^\S\n]*(?=\S)/,
10
+ /---+[^\S\v\f\r\n]*\r?\n[^\S\n]*(?=\S)/y,
11
11
  inits([
12
12
  rewrite(
13
13
  ({ context }) => {
@@ -23,7 +23,7 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
23
23
  block(
24
24
  union([
25
25
  validate(({ context }) => context.header ?? true,
26
- focus(/^---[^\S\v\f\r\n]*\r?\n(?:[A-Za-z][0-9A-Za-z]*(?:-[A-Za-z][0-9A-Za-z]*)*:[ \t]+\S[^\v\f\r\n]*\r?\n){1,100}---[^\S\v\f\r\n]*(?:$|\r?\n)/,
26
+ focus(/---[^\S\v\f\r\n]*\r?\n(?:[A-Za-z][0-9A-Za-z]*(?:-[A-Za-z][0-9A-Za-z]*)*:[ \t]+\S[^\v\f\r\n]*\r?\n){1,100}---[^\S\v\f\r\n]*(?:$|\r?\n)/y,
27
27
  convert(source =>
28
28
  normalize(source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n'))).replace(/(\S)\s+$/mg, '$1'),
29
29
  fmap(
@@ -48,7 +48,7 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
48
48
  ]];
49
49
  },
50
50
  ]))),
51
- clear(str(/^[^\S\v\f\r\n]*\r?\n/)),
51
+ clear(str(/[^\S\v\f\r\n]*\r?\n/y)),
52
52
  ])));
53
53
 
54
54
  const field: MarkdownParser.HeaderParser.FieldParser = line(({ context: { source, position } }) => {
@@ -16,14 +16,15 @@ describe('Unit: parser/inline/autolink/account', () => {
16
16
  assert.deepStrictEqual(inspect(parser('@-'), ctx), [['@'], '-']);
17
17
  assert.deepStrictEqual(inspect(parser('@.'), ctx), [['@'], '.']);
18
18
  assert.deepStrictEqual(inspect(parser('@0'), ctx), [['@0'], '']);
19
- assert.deepStrictEqual(inspect(parser('@a@'), ctx), [['@a@'], '']);
20
- assert.deepStrictEqual(inspect(parser('@a@b'), ctx), [['@a@b'], '']);
21
- assert.deepStrictEqual(inspect(parser('@a@b@c'), ctx), [['@a@b@c'], '']);
22
- assert.deepStrictEqual(inspect(parser('@ab@'), ctx), [['@ab@'], '']);
23
- assert.deepStrictEqual(inspect(parser('@a@b'), ctx), [['@a@b'], '']);
19
+ assert.deepStrictEqual(inspect(parser('@a@'), ctx), [['@a'], '@']);
20
+ assert.deepStrictEqual(inspect(parser('@a@b'), ctx), [['@a'], '@b']);
21
+ assert.deepStrictEqual(inspect(parser('@a@b@c'), ctx), [['@a'], '@b@c']);
22
+ assert.deepStrictEqual(inspect(parser('@ab@'), ctx), [['@ab'], '@']);
24
23
  assert.deepStrictEqual(inspect(parser('@@'), ctx), [['@@'], '']);
25
24
  assert.deepStrictEqual(inspect(parser('@@a'), ctx), [['@@a'], '']);
26
25
  assert.deepStrictEqual(inspect(parser('@@@a'), ctx), [['@@@a'], '']);
26
+ assert.deepStrictEqual(inspect(parser('@#'), ctx), [['@', '#'], '']);
27
+ assert.deepStrictEqual(inspect(parser('@#a'), ctx), [['@', '<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
27
28
  assert.deepStrictEqual(inspect(parser(' @a'), ctx), undefined);
28
29
  });
29
30
 
@@ -37,8 +38,8 @@ describe('Unit: parser/inline/autolink/account', () => {
37
38
  assert.deepStrictEqual(inspect(parser('@a--b'), ctx), [['<a class="account" href="/@a">@a</a>'], '--b']);
38
39
  assert.deepStrictEqual(inspect(parser('@a.'), ctx), [['<a class="account" href="/@a">@a</a>'], '.']);
39
40
  assert.deepStrictEqual(inspect(parser('@a.domain.com'), ctx), [['<a class="account" href="/@a.domain.com">@a.domain.com</a>'], '']);
40
- assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['<a class="account" href="/@http">@http</a>'], '://host']);
41
- assert.deepStrictEqual(inspect(parser('@ttp://host'), ctx), [['<a class="account" href="/@ttp">@ttp</a>'], '://host']);
41
+ assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http'], '://host']);
42
+ assert.deepStrictEqual(inspect(parser('@ttp://host'), ctx), [ [ '@ttp' ], '://host' ]);
42
43
  assert.deepStrictEqual(inspect(parser('@domain/a'), ctx), [['<a class="account" href="https://domain/@a" target="_blank">@domain/a</a>'], '']);
43
44
  assert.deepStrictEqual(inspect(parser('@domain.com/a'), ctx), [['<a class="account" href="https://domain.com/@a" target="_blank">@domain.com/a</a>'], '']);
44
45
  });
@@ -1,5 +1,5 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State } from '../../context';
2
+ import { State, Backtrack } from '../../context';
3
3
  import { union, tails, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
4
4
  import { unsafelink } from '../link';
5
5
  import { str } from '../../source';
@@ -9,17 +9,20 @@ import { define } from 'typed-dom/dom';
9
9
 
10
10
  export const account: AutolinkParser.AccountParser = lazy(() => rewrite(
11
11
  open(
12
- '@',
12
+ /(?<![0-9a-z])@/yi,
13
13
  tails([
14
- str(/^[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//i),
15
- str(/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*/i),
16
- ])),
14
+ str(/[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi),
15
+ str(/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![0-9a-z@#]|>>|:\S)/yi),
16
+ ]),
17
+ false,
18
+ [3 | Backtrack.autolink]),
17
19
  union([
18
20
  constraint(State.autolink, state(State.autolink, fmap(convert(
19
21
  source =>
20
- `[${source}]{ ${source.includes('/')
21
- ? `https://${source.slice(1).replace('/', '/@')}`
22
- : `/${source}`
22
+ `[${source}]{ ${
23
+ source.includes('/')
24
+ ? `https://${source.slice(1).replace('/', '/@')}`
25
+ : `/${source}`
23
26
  } }`,
24
27
  unsafelink,
25
28
  false),
@@ -18,7 +18,7 @@ describe('Unit: parser/inline/autolink/anchor', () => {
18
18
  assert.deepStrictEqual(inspect(parser('>>https://host'), ctx), undefined);
19
19
  assert.deepStrictEqual(inspect(parser('>>tel:1234567890'), ctx), undefined);
20
20
  assert.deepStrictEqual(inspect(parser('>>>'), ctx), undefined);
21
- assert.deepStrictEqual(inspect(parser('a>>0'), ctx), [['a>>0'], '']);
21
+ assert.deepStrictEqual(inspect(parser('a>>0'), ctx), [['a'], '>>0']);
22
22
  assert.deepStrictEqual(inspect(parser(' >>0'), ctx), undefined);
23
23
  });
24
24
 
@@ -1,7 +1,8 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State } from '../../context';
3
- import { union, state, constraint, validate, focus, convert, fmap, lazy } from '../../../combinator';
2
+ import { State, Backtrack } from '../../context';
3
+ import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
4
4
  import { unsafelink } from '../link';
5
+ import { str } from '../../source';
5
6
  import { define } from 'typed-dom/dom';
6
7
 
7
8
  // Timeline(pseudonym): user/tid
@@ -14,18 +15,21 @@ import { define } from 'typed-dom/dom';
14
15
  // 内部表現はUnixTimeに統一する(時系列順)
15
16
  // 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
16
17
 
17
- export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>',
18
- focus(
19
- /^>>(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9a-z@#:])/i,
20
- union([
21
- constraint(State.autolink, state(State.autolink, fmap(convert(
22
- source =>
23
- `[${source}]{ ${source.includes('/')
24
- ? `/@${source.slice(2).replace('/', '/timeline?at=')}`
25
- : `?at=${source.slice(2)}`
26
- } }`,
27
- unsafelink,
28
- false),
29
- ([el]) => [define(el, { class: 'anchor' })]))),
30
- ({ context: { source } }) => [[source]],
31
- ]))));
18
+ export const anchor: AutolinkParser.AnchorParser = lazy(() => rewrite(
19
+ open(
20
+ /(?<![0-9a-z])>>/yi,
21
+ str(/(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9a-z@#]|>>|:\S)/yi),
22
+ false,
23
+ [3 | Backtrack.autolink]),
24
+ union([
25
+ constraint(State.autolink, state(State.autolink, fmap(convert(
26
+ source =>
27
+ `[${source}]{ ${source.includes('/')
28
+ ? `/@${source.slice(2).replace('/', '/timeline?at=')}`
29
+ : `?at=${source.slice(2)}`
30
+ } }`,
31
+ unsafelink,
32
+ false),
33
+ ([el]) => [define(el, { class: 'anchor' })]))),
34
+ ({ context: { source } }) => [[source]],
35
+ ])));
@@ -10,19 +10,19 @@ describe('Unit: parser/inline/autolink/channel', () => {
10
10
 
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser(''), ctx), undefined);
13
- assert.deepStrictEqual(inspect(parser('@a@'), ctx), [['@a@'], '']);
14
- assert.deepStrictEqual(inspect(parser('@a@b'), ctx), [['@a@b'], '']);
15
- assert.deepStrictEqual(inspect(parser('@a#'), ctx), [['@a#'], '']);
16
- assert.deepStrictEqual(inspect(parser('@a#1'), ctx), [['@a#1'], '']);
17
- assert.deepStrictEqual(inspect(parser('@a#b@'), ctx), [['@a#b@'], '']);
18
- assert.deepStrictEqual(inspect(parser('@a#1@b'), ctx), [['@a#1@b'], '']);
19
- assert.deepStrictEqual(inspect(parser('@a#b#'), ctx), [['@a#b#'], '']);
20
- assert.deepStrictEqual(inspect(parser('@a#b#1'), ctx), [['@a#b#1'], '']);
13
+ assert.deepStrictEqual(inspect(parser('@a@'), ctx), [['@a'], '@']);
14
+ assert.deepStrictEqual(inspect(parser('@a@b'), ctx), [['@a'], '@b']);
15
+ assert.deepStrictEqual(inspect(parser('@a#'), ctx), [['@a'], '#']);
16
+ assert.deepStrictEqual(inspect(parser('@a#1'), ctx), [['@a'], '#1']);
17
+ assert.deepStrictEqual(inspect(parser('@a#b@'), ctx), [['@a'], '#b@']);
18
+ assert.deepStrictEqual(inspect(parser('@a#1@b'), ctx), [['@a'], '#1@b']);
21
19
  assert.deepStrictEqual(inspect(parser(' @a#b'), ctx), undefined);
22
20
  });
23
21
 
24
22
  it('valid', () => {
25
23
  assert.deepStrictEqual(inspect(parser('@a#b'), ctx), [['<a class="channel" href="/@a?ch=b">@a#b</a>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('@a#b#'), ctx), [['<a class="channel" href="/@a?ch=b">@a#b</a>'], '#']);
25
+ assert.deepStrictEqual(inspect(parser('@a#b#1'), ctx), [['<a class="channel" href="/@a?ch=b">@a#b</a>'], '#1']);
26
26
  assert.deepStrictEqual(inspect(parser('@a#b#c'), ctx), [['<a class="channel" href="/@a?ch=b+c">@a#b#c</a>'], '']);
27
27
  assert.deepStrictEqual(inspect(parser('@domain/a#b'), ctx), [['<a class="channel" href="https://domain/@a?ch=b" target="_blank">@domain/a#b</a>'], '']);
28
28
  });
@@ -1,22 +1,47 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State } from '../../context';
3
- import { sequence, some, constraint, validate, bind } from '../../../combinator';
4
- import { account } from './account';
5
- import { hashtag } from './hashtag';
6
- import { stringify } from '../../util';
2
+ import { State, Backtrack } from '../../context';
3
+ import { union, tails, sequence, some, state, constraint, verify, rewrite, open, convert, fmap, lazy } from '../../../combinator';
4
+ import { unsafelink } from '../link';
5
+ import { emoji } from './hashtag';
6
+ import { str } from '../../source';
7
7
  import { define } from 'typed-dom/dom';
8
8
 
9
9
  // https://example/@user?ch=a+b must be a user channel page or a redirect page going there.
10
10
 
11
- export const channel: AutolinkParser.ChannelParser = validate('@',
12
- constraint(State.autolink, bind(
11
+ export const channel: AutolinkParser.ChannelParser = lazy(() => rewrite(
13
12
  sequence([
14
- account,
15
- some(hashtag),
13
+ open(
14
+ /(?<![0-9a-z])@/yi,
15
+ tails([
16
+ str(/[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*\//yi),
17
+ str(/[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*(?![0-9a-z@]|>>|:\S)/yi),
18
+ ]),
19
+ false,
20
+ [3 | Backtrack.autolink]),
21
+ some(open(
22
+ '#',
23
+ verify(
24
+ str(new RegExp([
25
+ /(?!['_])(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji))+(?![0-9a-z@]|>>|:\S|[^\p{C}\p{S}\p{P}\s]|emoji)/yu.source,
26
+ ].join('').replace(/emoji/g, emoji), 'yu')),
27
+ ([source]) => !/^[0-9]{1,4}$|^[0-9]{5}/.test(source)),
28
+ false,
29
+ [3 | Backtrack.autolink])),
16
30
  ]),
17
- (es: [HTMLAnchorElement]) => {
18
- const source = stringify(es);
19
- const el = es[0];
20
- const url = `${el.getAttribute('href')}?ch=${source.slice(source.indexOf('#') + 1).replace(/#/g, '+')}`;
21
- return [[define(el, { class: 'channel', href: url }, source)]];
22
- })));
31
+ union([
32
+ constraint(State.autolink, state(State.autolink, fmap(convert(
33
+ source =>
34
+ `[${source}]{ ${
35
+ source.includes('/')
36
+ ? `https://${source.slice(1, source.indexOf('#')).replace('/', '/@')}`
37
+ : `/${source.slice(0, source.indexOf('#'))}`
38
+ } }`,
39
+ unsafelink,
40
+ false),
41
+ ([el], { source, position, range = 0 }) => {
42
+ const src = source.slice(position - range, position);
43
+ const url = `${el.getAttribute('href')}?ch=${src.slice(src.indexOf('#') + 1).replace(/#/g, '+')}`;
44
+ return [define(el, { class: 'channel', href: url }, src)];
45
+ }))),
46
+ ({ context: { source } }) => [[source]],
47
+ ])));
@@ -10,23 +10,25 @@ describe('Unit: parser/inline/autolink/email', () => {
10
10
 
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser(''), ctx), undefined);
13
- assert.deepStrictEqual(inspect(parser('a@'), ctx), [['a@'], '']);
14
- assert.deepStrictEqual(inspect(parser('a@+'), ctx), [['a@'], '+']);
15
- assert.deepStrictEqual(inspect(parser('a@_'), ctx), [['a@'], '_']);
16
- assert.deepStrictEqual(inspect(parser('a@-'), ctx), [['a@'], '-']);
17
- assert.deepStrictEqual(inspect(parser('a@.'), ctx), [['a@'], '.']);
18
- assert.deepStrictEqual(inspect(parser('a@b@'), ctx), [['a@b@'], '']);
19
- assert.deepStrictEqual(inspect(parser('a@bc@'), ctx), [['a@bc@'], '']);
20
- assert.deepStrictEqual(inspect(parser('a@b@c'), ctx), [['a@b@c'], '']);
21
- assert.deepStrictEqual(inspect(parser('a@b#'), ctx), [['a@b#'], '']);
22
- assert.deepStrictEqual(inspect(parser('a@b#1'), ctx), [['a@b#1'], '']);
23
- assert.deepStrictEqual(inspect(parser('a@@'), ctx), [['a@@'], '']);
24
- assert.deepStrictEqual(inspect(parser('a@@b'), ctx), [['a@@b'], '']);
13
+ assert.deepStrictEqual(inspect(parser('a@'), ctx), [['a'], '@']);
14
+ assert.deepStrictEqual(inspect(parser('a@+'), ctx), [['a'], '@+']);
15
+ assert.deepStrictEqual(inspect(parser('a@_'), ctx), [['a'], '@_']);
16
+ assert.deepStrictEqual(inspect(parser('a@-'), ctx), [['a'], '@-']);
17
+ assert.deepStrictEqual(inspect(parser('a@.'), ctx), [['a'], '@.']);
18
+ assert.deepStrictEqual(inspect(parser('a@b@'), ctx), [['a'], '@b@']);
19
+ assert.deepStrictEqual(inspect(parser('a@bc@'), ctx), [['a'], '@bc@']);
20
+ assert.deepStrictEqual(inspect(parser('a@b@c'), ctx), [['a'], '@b@c']);
21
+ assert.deepStrictEqual(inspect(parser('a@b#'), ctx), [['a'], '@b#']);
22
+ assert.deepStrictEqual(inspect(parser('a@b#1'), ctx), [['a'], '@b#1']);
23
+ assert.deepStrictEqual(inspect(parser('a@@'), ctx), [['a@', '@'], '']);
24
+ assert.deepStrictEqual(inspect(parser('a@@b'), ctx), [['a@', '<a class="account" href="/@b">@b</a>'], '']);
25
25
  assert.deepStrictEqual(inspect(parser('a+@b'), ctx), [['a'], '+@b']);
26
26
  assert.deepStrictEqual(inspect(parser('a__b@c'), ctx), [['a'], '__b@c']);
27
27
  assert.deepStrictEqual(inspect(parser('a..b@c'), ctx), [['a'], '..b@c']);
28
28
  assert.deepStrictEqual(inspect(parser('a++b@c'), ctx), [['a'], '++b@c']);
29
- assert.deepStrictEqual(inspect(parser(`a@${'b'.repeat(64)}`), ctx), [[`a@${'b'.repeat(64)}`], '']);
29
+ assert.deepStrictEqual(inspect(parser('a@http://host'), ctx), [['a'], '@http://host']);
30
+ assert.deepStrictEqual(inspect(parser('a@ttp://host'), ctx), [['a'], '@ttp://host']);
31
+ assert.deepStrictEqual(inspect(parser(`a@${'b'.repeat(64)}`), ctx), [['a'], `@${'b'.repeat(64)}`]);
30
32
  assert.deepStrictEqual(inspect(parser(' a@b'), ctx), undefined);
31
33
  });
32
34
 
@@ -44,8 +46,6 @@ describe('Unit: parser/inline/autolink/email', () => {
44
46
  assert.deepStrictEqual(inspect(parser('a@b.'), ctx), [['<a class="email" href="mailto:a@b">a@b</a>'], '.']);
45
47
  assert.deepStrictEqual(inspect(parser('a@b.c'), ctx), [['<a class="email" href="mailto:a@b.c">a@b.c</a>'], '']);
46
48
  assert.deepStrictEqual(inspect(parser('a@b..c'), ctx), [['<a class="email" href="mailto:a@b">a@b</a>'], '..c']);
47
- assert.deepStrictEqual(inspect(parser('a@http://host'), ctx), [['<a class="email" href="mailto:a@http">a@http</a>'], '://host']);
48
- assert.deepStrictEqual(inspect(parser('a@ttp://host'), ctx), [['<a class="email" href="mailto:a@ttp">a@ttp</a>'], '://host']);
49
49
  assert.deepStrictEqual(inspect(parser('ab+cd@0'), ctx), [['<a class="email" href="mailto:ab+cd@0">ab+cd@0</a>'], '']);
50
50
  });
51
51