securemark 0.283.7 → 0.285.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.
package/markdown.d.ts CHANGED
@@ -652,8 +652,8 @@ export namespace MarkdownParser {
652
652
  InlineParser.TemplateParser,
653
653
  InlineParser.RemarkParser,
654
654
  InlineParser.ExtensionParser,
655
- InlineParser.RubyParser,
656
655
  InlineParser.LinkParser.TextLinkParser,
656
+ InlineParser.RubyParser,
657
657
  InlineParser.HTMLParser,
658
658
  InlineParser.InsertionParser,
659
659
  InlineParser.DeletionParser,
@@ -661,6 +661,7 @@ export namespace MarkdownParser {
661
661
  InlineParser.EmStrongParser,
662
662
  InlineParser.StrongParser,
663
663
  InlineParser.EmphasisParser,
664
+ InlineParser.ItalicParser,
664
665
  InlineParser.MathParser,
665
666
  InlineParser.CodeParser,
666
667
  InlineParser.HTMLEntityParser,
@@ -815,20 +816,6 @@ export namespace MarkdownParser {
815
816
  ]> {
816
817
  }
817
818
  }
818
- export interface RubyParser extends
819
- // [AB](a b)
820
- Inline<'ruby'>,
821
- Parser<HTMLElement, Context, [
822
- Parser<string[], Context, []>,
823
- Parser<string[], Context, []>,
824
- ]> {
825
- }
826
- export namespace RubyParser {
827
- export interface TextParser extends
828
- Inline<'ruby/text'>,
829
- Parser<string[], Context, []> {
830
- }
831
- }
832
819
  export interface LinkParser extends
833
820
  // { uri }
834
821
  // [abc]{uri nofollow}
@@ -978,6 +965,20 @@ export namespace MarkdownParser {
978
965
  }
979
966
  }
980
967
  }
968
+ export interface RubyParser extends
969
+ // [AB](a b)
970
+ Inline<'ruby'>,
971
+ Parser<HTMLElement, Context, [
972
+ Parser<string[], Context, []>,
973
+ Parser<string[], Context, []>,
974
+ ]> {
975
+ }
976
+ export namespace RubyParser {
977
+ export interface TextParser extends
978
+ Inline<'ruby/text'>,
979
+ Parser<string[], Context, []> {
980
+ }
981
+ }
981
982
  export interface HTMLParser extends
982
983
  // Allow: wbr, bdo, bdi
983
984
  // <bdi>abc</bdi>
@@ -1015,7 +1016,7 @@ export namespace MarkdownParser {
1015
1016
  Inline<'insertion'>,
1016
1017
  Parser<HTMLElement | string, Context, [
1017
1018
  InlineParser,
1018
- InlineParser,
1019
+ InsertionParser,
1019
1020
  ]> {
1020
1021
  }
1021
1022
  export interface DeletionParser extends
@@ -1023,7 +1024,7 @@ export namespace MarkdownParser {
1023
1024
  Inline<'deletion'>,
1024
1025
  Parser<HTMLElement | string, Context, [
1025
1026
  InlineParser,
1026
- InlineParser,
1027
+ DeletionParser,
1027
1028
  ]> {
1028
1029
  }
1029
1030
  export interface MarkParser extends
@@ -1066,6 +1067,14 @@ export namespace MarkdownParser {
1066
1067
  ]>,
1067
1068
  ]> {
1068
1069
  }
1070
+ export interface ItalicParser extends
1071
+ // ///abc///
1072
+ Inline<'italic'>,
1073
+ Parser<HTMLElement | string, Context, [
1074
+ InlineParser,
1075
+ ItalicParser,
1076
+ ]> {
1077
+ }
1069
1078
  export interface MathParser extends
1070
1079
  // $expr$
1071
1080
  // ${expr}$
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.283.7",
3
+ "version": "0.285.0",
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",
@@ -31,11 +31,11 @@ export const enum Recursion {
31
31
  export const enum Backtrack {
32
32
  template = 7 << 2,
33
33
  index = 6 << 2,
34
- ruby = 5 << 2,
35
- link = 4 << 2,
34
+ link = 5 << 2,
35
+ ruby = 4 << 2,
36
36
  media = 3 << 2,
37
- url = 2 << 2,
38
- bracket = 1 << 2,
37
+ bracket = 2 << 2,
38
+ url = 1 << 2,
39
39
  }
40
40
 
41
41
  export const enum Command {
@@ -16,7 +16,7 @@ describe('Unit: parser/inline/autolink/url', () => {
16
16
  assert.deepStrictEqual(inspect(parser('Http://host')), [['Http'], '://host']);
17
17
  //assert.deepStrictEqual(inspect(parser('http://[::ffff:0:0%1]')), [['<a class="invalid">http://[::ffff:0:0%1]</a>'], '']);
18
18
  //assert.deepStrictEqual(inspect(parser('http://[::ffff:0:0/96]')), [['<a class="invalid">http://[::ffff:0:0/96]</a>'], '']);
19
- assert.deepStrictEqual(inspect(parser(' http://a')), undefined);
19
+ assert.deepStrictEqual(inspect(parser(' http://host')), undefined);
20
20
  });
21
21
 
22
22
  it('basic', () => {
@@ -58,7 +58,7 @@ describe('Unit: parser/inline/bracket', () => {
58
58
  assert.deepStrictEqual(inspect(parser('[]')), [['[', ']'], '']);
59
59
  assert.deepStrictEqual(inspect(parser('[a')), [['[', 'a'], '']);
60
60
  assert.deepStrictEqual(inspect(parser('[a]')), [['[', 'a', ']'], '']);
61
- assert.deepStrictEqual(inspect(parser('[==]')), [['[', '==', ']'], '']);
61
+ assert.deepStrictEqual(inspect(parser('[==]')), [['[', '=', '=', ']'], '']);
62
62
  assert.deepStrictEqual(inspect(parser('[$]$')), [['[', '<span class="math" translate="no" data-src="$]$">$]$</span>'], '']);
63
63
  assert.deepStrictEqual(inspect(parser(']')), undefined);
64
64
  });
@@ -68,7 +68,7 @@ describe('Unit: parser/inline/bracket', () => {
68
68
  assert.deepStrictEqual(inspect(parser('{}')), [['{', '}'], '']);
69
69
  assert.deepStrictEqual(inspect(parser('{a')), [['{', 'a'], '']);
70
70
  assert.deepStrictEqual(inspect(parser('{a}')), [['{', 'a', '}'], '']);
71
- assert.deepStrictEqual(inspect(parser('{==}')), [['{', '==', '}'], '']);
71
+ assert.deepStrictEqual(inspect(parser('{==}')), [['{', '=', '=', '}'], '']);
72
72
  assert.deepStrictEqual(inspect(parser('}')), undefined);
73
73
  });
74
74
 
@@ -1,19 +1,20 @@
1
1
  import { DeletionParser } from '../inline';
2
- import { Recursion } from '../context';
3
- import { union, some, creation, precedence, surround, open, lazy } from '../../combinator';
2
+ import { Recursion, Command } from '../context';
3
+ import { union, some, creation, precedence, validate, surround, open, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { str } from '../source';
6
5
  import { blankWith } from '../visibility';
7
- import { unshift } from 'spica/array';
6
+ import { repeat } from '../util';
7
+ import { push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
- export const deletion: DeletionParser = lazy(() => creation(1, Recursion.inline, surround(
11
- str('~~', '~'),
12
- precedence(0,
13
- some(union([
14
- some(inline, blankWith('\n', '~~')),
15
- open('\n', some(inline, '~'), true),
16
- ]))),
17
- str('~~'), false,
18
- ([, bs], rest) => [[html('del', defrag(bs))], rest],
19
- ([as, bs], rest) => [unshift(as, bs), rest])));
10
+ export const deletion: DeletionParser = lazy(() => creation(1, Recursion.inline, validate('~~',
11
+ precedence(0, repeat('~~', surround(
12
+ '',
13
+ some(union([
14
+ some(inline, blankWith('\n', '~~')),
15
+ open('\n', some(deletion, '~'), true),
16
+ ])),
17
+ '~~', false,
18
+ ([, bs], rest) => [bs, rest],
19
+ ([, bs], rest) => [push(bs, [Command.Escape]), rest]),
20
+ nodes => [html('del', defrag(nodes))])))));
@@ -5,14 +5,14 @@ import { inline } from '../inline';
5
5
  import { emstrong } from './emstrong';
6
6
  import { strong } from './strong';
7
7
  import { str } from '../source';
8
- import { startTight, blankWith } from '../visibility';
8
+ import { tightStart, blankWith } from '../visibility';
9
9
  import { unshift } from 'spica/array';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const emphasis: EmphasisParser = lazy(() => creation(1, Recursion.inline, surround(
13
13
  str('*', '*'),
14
14
  precedence(0,
15
- startTight(some(union([
15
+ tightStart(some(union([
16
16
  strong,
17
17
  some(inline, blankWith('*')),
18
18
  open(some(inline, '*'), union([
@@ -0,0 +1,115 @@
1
+ import { emstrong } from './emstrong';
2
+ import { some } from '../../combinator';
3
+ import { inspect } from '../../debug.test';
4
+
5
+ describe('Unit: parser/inline/emstrong', () => {
6
+ describe('emstrong', () => {
7
+ const parser = (source: string) => some(emstrong)({ source, context: {} });
8
+
9
+ it('invalid', () => {
10
+ assert.deepStrictEqual(inspect(parser('***')), undefined);
11
+ assert.deepStrictEqual(inspect(parser('***a')), [['***', 'a'], '']);
12
+ assert.deepStrictEqual(inspect(parser('***a ***')), [['***', 'a', ' ', '***'], '']);
13
+ assert.deepStrictEqual(inspect(parser('***a ***')), [['***', 'a', ' ', ' ', '***'], '']);
14
+ assert.deepStrictEqual(inspect(parser('***a\n***')), [['***', 'a', '<br>', '***'], '']);
15
+ assert.deepStrictEqual(inspect(parser('***a\\ ***')), [['***', 'a', ' ', '***'], '']);
16
+ assert.deepStrictEqual(inspect(parser('***a\\\n***')), [['***', 'a', '<br>', '***'], '']);
17
+ assert.deepStrictEqual(inspect(parser('*** ***')), undefined);
18
+ assert.deepStrictEqual(inspect(parser('*** a***')), undefined);
19
+ assert.deepStrictEqual(inspect(parser('*** a ***')), undefined);
20
+ assert.deepStrictEqual(inspect(parser('***\n***')), undefined);
21
+ assert.deepStrictEqual(inspect(parser('***\na***')), undefined);
22
+ assert.deepStrictEqual(inspect(parser('***\\ a***')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('***\\\na***')), undefined);
24
+ assert.deepStrictEqual(inspect(parser('***<wbr>a***')), undefined);
25
+ assert.deepStrictEqual(inspect(parser(' ***a***')), undefined);
26
+ });
27
+
28
+ it('basic', () => {
29
+ assert.deepStrictEqual(inspect(parser('***a***')), [['<em><strong>a</strong></em>'], '']);
30
+ assert.deepStrictEqual(inspect(parser('***ab***')), [['<em><strong>ab</strong></em>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('***a****')), [['<em><strong>a</strong></em>'], '*']);
32
+ assert.deepStrictEqual(inspect(parser('***a\nb***')), [['<em><strong>a<br>b</strong></em>'], '']);
33
+ assert.deepStrictEqual(inspect(parser('***a\\\nb***')), [['<em><strong>a<br>b</strong></em>'], '']);
34
+ });
35
+
36
+ it('nest', () => {
37
+ assert.deepStrictEqual(inspect(parser('***`a`***')), [['<em><strong><code data-src="`a`">a</code></strong></em>'], '']);
38
+ assert.deepStrictEqual(inspect(parser('***(*a*)***')), [['<em><strong><span class="paren">(<em>a</em>)</span></strong></em>'], '']);
39
+ assert.deepStrictEqual(inspect(parser('***(**a**)***')), [['<em><strong><span class="paren">(<strong>a</strong>)</span></strong></em>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('***(***a***)***')), [['<em><strong><span class="paren">(<em><strong>a</strong></em>)</span></strong></em>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('***a*')), [['**', '<em>a</em>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('***a*b')), [['**', '<em>a</em>', 'b'], '']);
43
+ assert.deepStrictEqual(inspect(parser('***a*b*')), [['**', '<em>a</em>', 'b', '*'], '']);
44
+ assert.deepStrictEqual(inspect(parser('***a*b*c')), [['**', '<em>a</em>', 'b', '*', 'c'], '']);
45
+ assert.deepStrictEqual(inspect(parser('***a*b*c*')), [['**', '<em>a</em>', 'b', '<em>c</em>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('***a*b*c**')), [['**', '<em>a</em>', 'b', '<em>c</em>', '*'], '']);
47
+ assert.deepStrictEqual(inspect(parser('***a*b*c***')), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('***a*b**')), [['<strong><em>a</em>b</strong>'], '']);
49
+ assert.deepStrictEqual(inspect(parser('***a*b**c')), [['<strong><em>a</em>b</strong>'], 'c']);
50
+ assert.deepStrictEqual(inspect(parser('***a**')), [['*', '<strong>a</strong>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('***a**b')), [['*', '<strong>a</strong>', 'b'], '']);
52
+ assert.deepStrictEqual(inspect(parser('***a**b*')), [['<em><strong>a</strong>b</em>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('***a**b**')), [['<em><strong>a</strong>b</em>'], '*']);
54
+ assert.deepStrictEqual(inspect(parser('***a**b**c')), [['*', '<strong>a</strong>', 'b', '**', 'c'], '']);
55
+ assert.deepStrictEqual(inspect(parser('***a**b**c*')), [['*', '<strong>a</strong>', 'b', '**', 'c', '*'], '']);
56
+ assert.deepStrictEqual(inspect(parser('***a**b**c**')), [['*', '<strong>a</strong>', 'b', '<strong>c</strong>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('***a**b**c***')), [['<em><strong>a</strong>b<strong>c</strong></em>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('***a **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
59
+ assert.deepStrictEqual(inspect(parser('***a\\ *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('***a\\ **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
61
+ assert.deepStrictEqual(inspect(parser('***a&Tab;*b****')), [['<em><strong>a\t<em>b</em></strong></em>'], '']);
62
+ assert.deepStrictEqual(inspect(parser('***a<wbr>*b****')), [['<em><strong>a<wbr><em>b</em></strong></em>'], '']);
63
+ assert.deepStrictEqual(inspect(parser('***a *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
64
+ assert.deepStrictEqual(inspect(parser('***a* **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
65
+ assert.deepStrictEqual(inspect(parser('***a*\\ **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
66
+ assert.deepStrictEqual(inspect(parser('***a*&Tab;**b****')), [['<strong><em>a</em>\t<strong>b</strong></strong>'], '']);
67
+ assert.deepStrictEqual(inspect(parser('***a*<wbr>**b****')), [['<strong><em>a</em><wbr><strong>b</strong></strong>'], '']);
68
+ assert.deepStrictEqual(inspect(parser('***a*b **')), [['**', '<em>a</em>', 'b'], ' **']);
69
+ assert.deepStrictEqual(inspect(parser('***a*b\\ **')), [['**', '<em>a</em>', 'b'], '\\ **']);
70
+ assert.deepStrictEqual(inspect(parser('***a**b*')), [['<em><strong>a</strong>b</em>'], '']);
71
+ assert.deepStrictEqual(inspect(parser('***a**b*c')), [['<em><strong>a</strong>b</em>'], 'c']);
72
+ assert.deepStrictEqual(inspect(parser('***a**b*c**')), [['<em><strong>a</strong>b</em>'], 'c**']);
73
+ assert.deepStrictEqual(inspect(parser('***a**b**c***')), [['<em><strong>a</strong>b<strong>c</strong></em>'], '']);
74
+ assert.deepStrictEqual(inspect(parser('***a**b**c***d')), [['<em><strong>a</strong>b<strong>c</strong></em>'], 'd']);
75
+ assert.deepStrictEqual(inspect(parser('***a** *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('***a**\\ *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
77
+ assert.deepStrictEqual(inspect(parser('***a**&Tab;*b**')), [['<em><strong>a</strong>\t<em>b</em></em>'], '']);
78
+ assert.deepStrictEqual(inspect(parser('***a**<wbr>*b**')), [['<em><strong>a</strong><wbr><em>b</em></em>'], '']);
79
+ assert.deepStrictEqual(inspect(parser('***a**b *')), [['*', '<strong>a</strong>', 'b'], ' *']);
80
+ assert.deepStrictEqual(inspect(parser('***a**b\\ *')), [['*', '<strong>a</strong>', 'b'], '\\ *']);
81
+ assert.deepStrictEqual(inspect(parser('***a*')), [['**', '<em>a</em>'], '']);
82
+ assert.deepStrictEqual(inspect(parser('***a**')), [['*', '<strong>a</strong>'], '']);
83
+ assert.deepStrictEqual(inspect(parser('***a***')), [['<em><strong>a</strong></em>'], '']);
84
+ assert.deepStrictEqual(inspect(parser('***a***b')), [['<em><strong>a</strong></em>'], 'b']);
85
+ assert.deepStrictEqual(inspect(parser('***a****')), [['<em><strong>a</strong></em>'], '*']);
86
+ assert.deepStrictEqual(inspect(parser('***a*****')), [['<em><strong>a</strong></em>'], '**']);
87
+ assert.deepStrictEqual(inspect(parser('***a******')), [['<em><strong>a</strong></em>'], '***']);
88
+ assert.deepStrictEqual(inspect(parser('****a***')), [['*', '<em><strong>a</strong></em>'], '']);
89
+ assert.deepStrictEqual(inspect(parser('****a***b')), [['*', '<em><strong>a</strong></em>'], 'b']);
90
+ assert.deepStrictEqual(inspect(parser('****a****')), [['<em><em><strong>a</strong></em></em>'], '']);
91
+ assert.deepStrictEqual(inspect(parser('****a****b')), [['<em><em><strong>a</strong></em></em>'], 'b']);
92
+ assert.deepStrictEqual(inspect(parser('*****a***')), [['**', '<em><strong>a</strong></em>'], '']);
93
+ assert.deepStrictEqual(inspect(parser('*****a***b')), [['**', '<em><strong>a</strong></em>'], 'b']);
94
+ assert.deepStrictEqual(inspect(parser('*****a****')), [['*', '<em><em><strong>a</strong></em></em>'], '']);
95
+ assert.deepStrictEqual(inspect(parser('*****a****b')), [['*', '<em><em><strong>a</strong></em></em>'], 'b']);
96
+ assert.deepStrictEqual(inspect(parser('*****a*****')), [['<strong><em><strong>a</strong></em></strong>'], '']);
97
+ assert.deepStrictEqual(inspect(parser('******a***')), [['***', '<em><strong>a</strong></em>'], '']);
98
+ assert.deepStrictEqual(inspect(parser('******a***b')), [['***', '<em><strong>a</strong></em>', 'b'], '']);
99
+ assert.deepStrictEqual(inspect(parser('******a****')), [['**', '<em><em><strong>a</strong></em></em>'], '']);
100
+ assert.deepStrictEqual(inspect(parser('******a****b')), [['**', '<em><em><strong>a</strong></em></em>'], 'b']);
101
+ assert.deepStrictEqual(inspect(parser('******a*****')), [['*', '<strong><em><strong>a</strong></em></strong>'], '']);
102
+ assert.deepStrictEqual(inspect(parser('******a*****b')), [['*', '<strong><em><strong>a</strong></em></strong>'], 'b']);
103
+ assert.deepStrictEqual(inspect(parser('******a******')), [['<em><strong><em><strong>a</strong></em></strong></em>'], '']);
104
+ assert.deepStrictEqual(inspect(parser('******a******b')), [['<em><strong><em><strong>a</strong></em></strong></em>'], 'b']);
105
+ assert.deepStrictEqual(inspect(parser('******a*b')), [['***', '**', '<em>a</em>', 'b'], '']);
106
+ assert.deepStrictEqual(inspect(parser('******a*b *')), [['***', '**', '<em>a</em>', 'b', ' ', '*'], '']);
107
+ assert.deepStrictEqual(inspect(parser('******a*b **')), [['***', '**', '<em>a</em>', 'b'], ' **']);
108
+ assert.deepStrictEqual(inspect(parser('******a*b ***')), [['***', '**', '<em>a</em>', 'b'], ' ***']);
109
+ assert.deepStrictEqual(inspect(parser('******a*b ****')), [['***', '**', '<em>a</em>', 'b'], ' ****']);
110
+ assert.deepStrictEqual(inspect(parser('******a*b *****')), [['***', '**', '<em>a</em>', 'b'], ' *****']);
111
+ });
112
+
113
+ });
114
+
115
+ });
@@ -1,14 +1,15 @@
1
1
  import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
2
- import { Recursion } from '../context';
2
+ import { Recursion, Command } from '../context';
3
3
  import { Result, IntermediateParser } from '../../combinator/data/parser';
4
- import { union, creation, precedence, some, surround, open, lazy, bind } from '../../combinator';
4
+ import { union, some, creation, precedence, validate, surround, open, lazy, bind } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
7
  import { emphasis } from './emphasis';
8
8
  import { str } from '../source';
9
- import { startTight, blankWith } from '../visibility';
9
+ import { tightStart, blankWith } from '../visibility';
10
+ import { repeat } from '../util';
10
11
  import { html, defrag } from 'typed-dom/dom';
11
- import { unshift } from 'spica/array';
12
+ import { unshift, push } from 'spica/array';
12
13
 
13
14
  const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
14
15
  some(inline, blankWith('**')),
@@ -27,36 +28,69 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
27
28
  ])),
28
29
  ])));
29
30
 
30
- export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, surround(
31
- str('***'),
32
- precedence(0,
33
- startTight(some(union([
34
- some(inline, blankWith('*')),
35
- open(some(inline, '*'), inline),
36
- ])))),
37
- str(/^\*{1,3}/), false,
38
- ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
39
- assert(cs.length === 1);
40
- switch (cs[0]) {
41
- case '***':
42
- return [[html('em', [html('strong', defrag(bs))])], rest];
43
- case '**':
44
- return bind<EmphasisParser>(
45
- subemphasis,
46
- (ds, rest) =>
47
- rest.slice(0, 1) === '*'
48
- ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds)))], rest.slice(1)]
49
- : [unshift(['*', html('strong', defrag(bs))], ds), rest])
50
- ({ source: rest, context }) ?? [['*', html('strong', defrag(bs))], rest];
51
- case '*':
52
- return bind<StrongParser>(
53
- substrong,
54
- (ds, rest) =>
55
- rest.slice(0, 2) === '**'
56
- ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
57
- : [unshift(['**', html('em', defrag(bs))], ds), rest])
58
- ({ source: rest, context }) ?? [['**', html('em', defrag(bs))], rest];
59
- }
60
- assert(false);
61
- },
62
- ([as, bs], rest) => [unshift(as, bs), rest])));
31
+ // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず早く閉じるよう解析しなければならない。
32
+ // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
33
+ export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, validate('***',
34
+ precedence(0, repeat('***', surround(
35
+ '',
36
+ tightStart(some(union([
37
+ some(inline, blankWith('*')),
38
+ open(some(inline, '*'), inline),
39
+ ]))),
40
+ str(/^\*{1,3}/), false,
41
+ ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
42
+ assert(cs.length === 1);
43
+ switch (cs[0]) {
44
+ case '***':
45
+ return [bs, rest];
46
+ case '**':
47
+ return bind<EmphasisParser>(
48
+ subemphasis,
49
+ (ds, rest) =>
50
+ rest.slice(0, 1) === '*'
51
+ ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds))), Command.Separator], rest.slice(1)]
52
+ : [push(unshift(['*', html('strong', defrag(bs))], ds), [Command.Separator]), rest])
53
+ ({ source: rest, context }) ?? [['*', html('strong', defrag(bs)), Command.Separator], rest];
54
+ case '*':
55
+ return bind<StrongParser>(
56
+ substrong,
57
+ (ds, rest) =>
58
+ rest.slice(0, 2) === '**'
59
+ ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds))), Command.Separator], rest.slice(2)]
60
+ : [push(unshift(['**', html('em', defrag(bs))], ds), [Command.Separator]), rest])
61
+ ({ source: rest, context }) ?? [['**', html('em', defrag(bs)), Command.Separator], rest];
62
+ }
63
+ assert(false);
64
+ },
65
+ ([as, bs], rest) => [push(unshift(as, bs), [Command.Escape]), rest]),
66
+ // 3以上の`*`に対してemの適用を保証する
67
+ nodes => [html('em', [html('strong', defrag(nodes))])],
68
+ (acc, rest, prefix, postfix, state) => {
69
+ const nodes = [];
70
+ let i = postfix;
71
+ if (state) while (i > 0) {
72
+ switch (i) {
73
+ case 1:
74
+ acc = [[html('em', acc.flat())]];
75
+ i -= 1;
76
+ break;
77
+ case 2:
78
+ acc = [[html('strong', acc.flat())]];
79
+ i -= 2;
80
+ break;
81
+ default:
82
+ acc = [[html('em', [html('strong', acc.flat())])]];
83
+ i -= 3;
84
+ }
85
+ }
86
+ if (prefix > postfix) {
87
+ nodes.push('*'.repeat(prefix - postfix));
88
+ }
89
+ for (let i = 0; i < acc.length; ++i) {
90
+ nodes.push(...acc[i]);
91
+ }
92
+ if (postfix > 0) {
93
+ rest = rest.slice(postfix);
94
+ }
95
+ return [nodes, rest];
96
+ })))));
@@ -4,7 +4,7 @@ import { union, inits, some, creation, precedence, state, constraint, validate,
4
4
  import { inline } from '../../inline';
5
5
  import { indexee, identity } from './indexee';
6
6
  import { txt, str } from '../../source';
7
- import { startTight, trimBlankNodeEnd } from '../../visibility';
7
+ import { tightStart, trimBlankNodeEnd } from '../../visibility';
8
8
  import { html, define, defrag } from 'typed-dom/dom';
9
9
 
10
10
  import IndexParser = ExtensionParser.IndexParser;
@@ -12,7 +12,7 @@ import IndexParser = ExtensionParser.IndexParser;
12
12
  export const index: IndexParser = lazy(() => constraint(State.index, false, creation(1, Recursion.ignore, fmap(indexee(surround(
13
13
  '[#',
14
14
  precedence(1, state(State.linkers | State.media,
15
- startTight(
15
+ tightStart(
16
16
  some(inits([
17
17
  inline,
18
18
  signature,
@@ -1,6 +1,6 @@
1
1
  import { ExtensionParser } from '../../inline';
2
2
  import { State, Recursion } from '../../context';
3
- import { union, constraint, creation, surround, clear, fmap } from '../../../combinator';
3
+ import { union, creation, constraint, surround, clear, fmap } from '../../../combinator';
4
4
  import { str } from '../../source';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
@@ -3,7 +3,7 @@ import { Recursion, Backtrack } from '../../context';
3
3
  import { union, some, creation, precedence, surround, lazy } from '../../../combinator';
4
4
  import { inline } from '../../inline';
5
5
  import { str } from '../../source';
6
- import { startTight } from '../../visibility';
6
+ import { tightStart } from '../../visibility';
7
7
  import { unshift } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
@@ -14,7 +14,7 @@ import { html, defrag } from 'typed-dom/dom';
14
14
  export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => creation(1, Recursion.inline, surround(
15
15
  str(/^\[[:^|]/),
16
16
  precedence(1,
17
- startTight(some(union([inline]), ']', [[']', 1]]))),
17
+ tightStart(some(union([inline]), ']', [[']', 1]]))),
18
18
  str(']'), false,
19
19
  ([, bs], rest) => [[
20
20
  html('span', {
@@ -3,7 +3,7 @@ import { Recursion } from '../context';
3
3
  import { union, subsequence, some, creation, precedence, validate, focus, surround, open, match, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
- import { isStartLooseNodes, blankWith } from '../visibility';
6
+ import { isLooseNodeStart, blankWith } from '../visibility';
7
7
  import { memoize } from 'spica/memoize';
8
8
  import { Clock } from 'spica/clock';
9
9
  import { unshift, push, splice } from 'spica/array';
@@ -219,7 +219,7 @@ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: strin
219
219
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag name "${tag}"`, as, bs, cs);
220
220
  if (cs.length === 0) return invalid('tag', `Missing the closing HTML tag "</${tag}>"`, as, bs, cs);
221
221
  if (bs.length === 0) return invalid('content', `Missing the content`, as, bs, cs);
222
- if (!isStartLooseNodes(bs)) return invalid('content', `Missing the visible content in the same line`, as, bs, cs);
222
+ if (!isLooseNodeStart(bs)) return invalid('content', `Missing the visible content in the same line`, as, bs, cs);
223
223
  const attrs = attributes('html', [], attrspecs[tag], as.slice(1, -1));
224
224
  return 'data-invalid-syntax' in attrs
225
225
  ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs)
@@ -1,19 +1,20 @@
1
1
  import { InsertionParser } from '../inline';
2
- import { Recursion } from '../context';
3
- import { union, some, creation, precedence, surround, open, lazy } from '../../combinator';
2
+ import { Recursion, Command } from '../context';
3
+ import { union, some, creation, precedence, validate, surround, open, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { str } from '../source';
6
5
  import { blankWith } from '../visibility';
7
- import { unshift } from 'spica/array';
6
+ import { repeat } from '../util';
7
+ import { push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
- export const insertion: InsertionParser = lazy(() => creation(1, Recursion.inline, surround(
11
- str('++', '+'),
12
- precedence(0,
13
- some(union([
14
- some(inline, blankWith('\n', '++')),
15
- open('\n', some(inline, '+'), true),
16
- ]))),
17
- str('++'), false,
18
- ([, bs], rest) => [[html('ins', defrag(bs))], rest],
19
- ([as, bs], rest) => [unshift(as, bs), rest])));
10
+ export const insertion: InsertionParser = lazy(() => creation(1, Recursion.inline, validate('++',
11
+ precedence(0, repeat('++', surround(
12
+ '',
13
+ some(union([
14
+ some(inline, blankWith('\n', '++')),
15
+ open('\n', some(insertion, '+'), true),
16
+ ])),
17
+ '++', false,
18
+ ([, bs], rest) => [bs, rest],
19
+ ([, bs], rest) => [push(bs, [Command.Escape]), rest]),
20
+ nodes => [html('ins', defrag(nodes))])))));