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/CHANGELOG.md +8 -0
- package/README.md +11 -11
- package/dist/index.js +182 -57
- package/markdown.d.ts +26 -17
- package/package.json +1 -1
- package/src/parser/context.ts +4 -4
- package/src/parser/inline/autolink/url.test.ts +1 -1
- package/src/parser/inline/bracket.test.ts +2 -2
- package/src/parser/inline/deletion.ts +15 -14
- package/src/parser/inline/emphasis.ts +2 -2
- package/src/parser/inline/emstrong.test.ts +115 -0
- package/src/parser/inline/emstrong.ts +71 -37
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/inline/extension/placeholder.ts +2 -2
- package/src/parser/inline/html.ts +2 -2
- package/src/parser/inline/insertion.ts +15 -14
- package/src/parser/inline/italic.test.ts +72 -0
- package/src/parser/inline/italic.ts +22 -0
- package/src/parser/inline/link.ts +1 -1
- package/src/parser/inline/mark.ts +22 -21
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/ruby.ts +6 -4
- package/src/parser/inline/strong.ts +2 -2
- package/src/parser/inline/template.ts +1 -1
- package/src/parser/inline.test.ts +12 -38
- package/src/parser/inline.ts +8 -4
- package/src/parser/source/text.ts +0 -3
- package/src/parser/util.ts +66 -1
- package/src/parser/visibility.ts +22 -19
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { italic } from './italic';
|
|
2
|
+
import { some } from '../../combinator';
|
|
3
|
+
import { inspect } from '../../debug.test';
|
|
4
|
+
|
|
5
|
+
describe('Unit: parser/inline/italic', () => {
|
|
6
|
+
describe('italic', () => {
|
|
7
|
+
const parser = (source: string) => some(italic)({ 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'], '\n///']);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('///a\\ ///')), [['///', 'a'], '\\ ///']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('///a\\\n///')), [['///', 'a'], '\\\n///']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser('///a/b')), [['///', 'a', '/', 'b'], '']);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser('///a//b')), [['///', 'a', '/', '/', 'b'], '']);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser('///a*b///')), [['///', 'a', '*', 'b', '/', '/', '/'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser('/// ///')), undefined);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser('/// a///')), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser('/// a ///')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('///\n///')), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('///\na///')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('///\\ a///')), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('///\\\na///')), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser('///<wbr>a///')), undefined);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser(' ///a///')), undefined);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('basic', () => {
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('///a///')), [['<i>a</i>'], '']);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('///ab///')), [['<i>ab</i>'], '']);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('///a////')), [['<i>a</i>'], '/']);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('///a\nb///')), [['<i>a<br>b</i>'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('///a\\\nb///')), [['<i>a<br>b</i>'], '']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('nest', () => {
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('////a///')), [['/', '<i>a</i>'], '']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser('////a///b')), [['/', '<i>a</i>'], 'b']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('////a////')), [['/', '<i>a</i>', '/'], '']);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('////a////b')), [['/', '<i>a</i>', '/'], 'b']);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('/////a///')), [['//', '<i>a</i>'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser('/////a///b')), [['//', '<i>a</i>'], 'b']);
|
|
46
|
+
assert.deepStrictEqual(inspect(parser('/////a////')), [['//', '<i>a</i>', '/'], '']);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser('/////a////b')), [['//', '<i>a</i>', '/'], 'b']);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('/////a/////')), [['//', '<i>a</i>', '//'], '']);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser('/////a/////b')), [['//', '<i>a</i>', '//'], 'b']);
|
|
50
|
+
assert.deepStrictEqual(inspect(parser('//////a///')), [['///', '<i>a</i>'], '']);
|
|
51
|
+
assert.deepStrictEqual(inspect(parser('//////a///b')), [['///', '<i>a</i>', 'b'], '']);
|
|
52
|
+
assert.deepStrictEqual(inspect(parser('//////a////')), [['///', '<i>a</i>', '/'], '']);
|
|
53
|
+
assert.deepStrictEqual(inspect(parser('//////a////b')), [['///', '<i>a</i>', '/', 'b'], '']);
|
|
54
|
+
assert.deepStrictEqual(inspect(parser('//////a/////')), [['///', '<i>a</i>', '/', '/'], '']);
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('//////a/////b')), [['///', '<i>a</i>', '/', '/', 'b'], '']);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('//////a//////')), [['<i><i>a</i></i>'], '']);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser('//////a///b///')), [['<i><i>a</i>b</i>'], '']);
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('///a ///b//////')), [['<i>a <i>b</i></i>'], '']);
|
|
59
|
+
assert.deepStrictEqual(inspect(parser('///a\\ ///b//////')), [['<i>a <i>b</i></i>'], '']);
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('///a //////b/////////')), [['<i>a <i><i>b</i></i></i>'], '']);
|
|
61
|
+
assert.deepStrictEqual(inspect(parser('///a ///b///c///')), [['<i>a <i>b</i>c</i>'], '']);
|
|
62
|
+
assert.deepStrictEqual(inspect(parser('///a ///b ///c/////////')), [['<i>a <i>b <i>c</i></i></i>'], '']);
|
|
63
|
+
assert.deepStrictEqual(inspect(parser('///a	///b//////')), [['<i>a\t<i>b</i></i>'], '']);
|
|
64
|
+
assert.deepStrictEqual(inspect(parser('///a<wbr>///b//////')), [['<i>a<wbr><i>b</i></i>'], '']);
|
|
65
|
+
assert.deepStrictEqual(inspect(parser('///`a`///')), [['<i><code data-src="`a`">a</code></i>'], '']);
|
|
66
|
+
assert.deepStrictEqual(inspect(parser('///(///a///)///')), [['<i><span class="paren">(<i>a</i>)</span></i>'], '']);
|
|
67
|
+
assert.deepStrictEqual(inspect(parser('///{http://host/}///')), [['<i><a class="url" href="http://host/" target="_blank">http://host/</a></i>'], '']);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ItalicParser } from '../inline';
|
|
2
|
+
import { Recursion, Command } from '../context';
|
|
3
|
+
import { union, some, creation, precedence, validate, surround, open, lazy } from '../../combinator';
|
|
4
|
+
import { inline } from '../inline';
|
|
5
|
+
import { tightStart, blankWith } from '../visibility';
|
|
6
|
+
import { repeat } from '../util';
|
|
7
|
+
import { push } from 'spica/array';
|
|
8
|
+
import { html, defrag } from 'typed-dom/dom';
|
|
9
|
+
|
|
10
|
+
// 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
|
|
11
|
+
// ある程度の長さのある文に使うのが望ましい。
|
|
12
|
+
export const italic: ItalicParser = lazy(() => creation(1, Recursion.inline, validate('///',
|
|
13
|
+
precedence(0, repeat('///', surround(
|
|
14
|
+
'',
|
|
15
|
+
tightStart(some(union([
|
|
16
|
+
some(inline, blankWith('///')),
|
|
17
|
+
open(some(inline, '/'), italic),
|
|
18
|
+
]))),
|
|
19
|
+
'///', false,
|
|
20
|
+
([, bs], rest) => [bs, rest],
|
|
21
|
+
([, bs], rest) => [push(bs, [Command.Escape]), rest]),
|
|
22
|
+
nodes => [html('i', defrag(nodes))])))));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../../markdown';
|
|
2
2
|
import { LinkParser } from '../inline';
|
|
3
3
|
import { State, Recursion, Backtrack } from '../context';
|
|
4
|
-
import { union, inits, tails, sequence, some,
|
|
4
|
+
import { union, inits, tails, sequence, some, creation, precedence, state, constraint, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { linebreak, unescsource, str } from '../source';
|
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
import { MarkParser } from '../inline';
|
|
2
|
-
import { State, Recursion } from '../context';
|
|
3
|
-
import { union, some, creation, precedence, constraint, surround, open, lazy } from '../../combinator';
|
|
2
|
+
import { State, Recursion, Command } from '../context';
|
|
3
|
+
import { union, some, creation, precedence, constraint, validate, surround, open, lazy } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { identity, signature } from './extension/indexee';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { tightStart, blankWith } from '../visibility';
|
|
7
|
+
import { repeat } from '../util';
|
|
8
|
+
import { push } from 'spica/array';
|
|
9
9
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
|
-
export const mark: MarkParser = lazy(() => constraint(State.mark, false, creation(1, Recursion.inline,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
el
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
export const mark: MarkParser = lazy(() => constraint(State.mark, false, creation(1, Recursion.inline, validate('==',
|
|
12
|
+
precedence(0, repeat('==', surround(
|
|
13
|
+
'',
|
|
14
|
+
tightStart(some(union([
|
|
15
|
+
some(inline, blankWith('==')),
|
|
16
|
+
open(some(inline, '='), mark),
|
|
17
|
+
]))),
|
|
18
|
+
'==', false,
|
|
19
|
+
([, bs], rest) => [bs, rest],
|
|
20
|
+
([, bs], rest) => [push(bs, [Command.Escape]), rest]),
|
|
21
|
+
(nodes, { id }) => {
|
|
22
|
+
const el = html('mark', defrag(nodes));
|
|
23
|
+
define(el, { id: identity('mark', id, signature(el)) });
|
|
24
|
+
return el.id
|
|
25
|
+
? [el, el.id && html('a', { href: `#${el.id}` })]
|
|
26
|
+
: [el];
|
|
27
|
+
}))))));
|
|
@@ -4,7 +4,7 @@ import { eval, exec } from '../../combinator/data/parser';
|
|
|
4
4
|
import { sequence, creation, surround, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
6
|
import { text as txt, str } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { isTightNodeStart } from '../visibility';
|
|
8
8
|
import { unshift, push } from 'spica/array';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
|
|
|
13
13
|
bind(surround('[', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
|
|
14
14
|
const ns = eval(text({ source, context }), [undefined])[0];
|
|
15
15
|
ns && ns.at(-1) === '' && ns.pop();
|
|
16
|
-
return ns &&
|
|
16
|
+
return ns && isTightNodeStart(ns) ? [[ns], rest] : undefined;
|
|
17
17
|
}),
|
|
18
18
|
bind(surround('(', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
|
|
19
19
|
const ns = eval(text({ source, context }), [undefined])[0];
|
|
@@ -26,7 +26,8 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
|
|
|
26
26
|
return [
|
|
27
27
|
html('ruby', attributes(texts, rubies), defrag(texts
|
|
28
28
|
.reduce((acc, _, i) =>
|
|
29
|
-
push(acc, unshift(
|
|
29
|
+
push(acc, unshift(
|
|
30
|
+
[texts[i]],
|
|
30
31
|
i < rubies.length && rubies[i]
|
|
31
32
|
? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
|
|
32
33
|
: [html('rt')]))
|
|
@@ -36,7 +37,8 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
|
|
|
36
37
|
return [
|
|
37
38
|
html('ruby', attributes(texts, rubies), defrag([...texts[0]]
|
|
38
39
|
.reduce((acc, _, i, texts) =>
|
|
39
|
-
push(acc, unshift(
|
|
40
|
+
push(acc, unshift(
|
|
41
|
+
[texts[i]],
|
|
40
42
|
i < rubies.length && rubies[i]
|
|
41
43
|
? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
|
|
42
44
|
: [html('rt')]))
|
|
@@ -4,14 +4,14 @@ import { union, some, creation, precedence, surround, open, lazy } from '../../c
|
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { emstrong } from './emstrong';
|
|
6
6
|
import { str } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { tightStart, blankWith } from '../visibility';
|
|
8
8
|
import { unshift } from 'spica/array';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const strong: StrongParser = lazy(() => creation(1, Recursion.inline, surround(
|
|
12
12
|
str('**', '*'),
|
|
13
13
|
precedence(0,
|
|
14
|
-
|
|
14
|
+
tightStart(some(union([
|
|
15
15
|
some(inline, blankWith('**')),
|
|
16
16
|
open(some(inline, '*'), union([
|
|
17
17
|
emstrong,
|
|
@@ -20,6 +20,6 @@ const bracket: TemplateParser.BracketParser = lazy(() => creation(0, Recursion.t
|
|
|
20
20
|
undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
|
|
21
21
|
surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true,
|
|
22
22
|
undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
|
|
23
|
-
surround(str('"'), precedence(2, some(escsource, /^"
|
|
23
|
+
surround(str('"'), precedence(2, some(escsource, /^["\n]/)), str('"'), true,
|
|
24
24
|
undefined, undefined, 3 | Backtrack.template),
|
|
25
25
|
])));
|
|
@@ -20,9 +20,6 @@ describe('Unit: parser/inline', () => {
|
|
|
20
20
|
it('nest', () => {
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('あ(A)')), [['あ', '(', 'A', ')'], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('あ(い)')), [['あ', '<span class="paren">(い)</span>'], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('+++a+++')), [['+++', 'a', '+++'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('~~~a~~~')), [['~~~', 'a', '~~~'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('===a===')), [['===', 'a', '==='], '']);
|
|
26
23
|
assert.deepStrictEqual(inspect(parser('* a*')), [['*', ' ', 'a', '*'], '']);
|
|
27
24
|
assert.deepStrictEqual(inspect(parser('** a**')), [['**', ' ', 'a', '**'], '']);
|
|
28
25
|
assert.deepStrictEqual(inspect(parser('*** a***')), [['***', ' ', 'a', '***'], '']);
|
|
@@ -47,6 +44,11 @@ describe('Unit: parser/inline', () => {
|
|
|
47
44
|
assert.deepStrictEqual(inspect(parser('*a ***b****')), [['<em>a <em><strong>b</strong></em></em>'], '']);
|
|
48
45
|
assert.deepStrictEqual(inspect(parser('*a ***b****c')), [['<em>a <em><strong>b</strong></em></em>', 'c'], '']);
|
|
49
46
|
assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser('**a*b')), [['**', 'a', '*', 'b'], '']);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('**a*b*')), [['**', 'a', '<em>b</em>'], '']);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser('**a*b*c')), [['**', 'a', '<em>b</em>', 'c'], '']);
|
|
50
|
+
assert.deepStrictEqual(inspect(parser('**a*b*c*')), [['**', 'a', '<em>b</em>', 'c', '*'], '']);
|
|
51
|
+
assert.deepStrictEqual(inspect(parser('**a*b*c**')), [['<strong>a<em>b</em>c</strong>'], '']);
|
|
50
52
|
assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
|
|
51
53
|
assert.deepStrictEqual(inspect(parser('**a*b**c')), [['**', 'a', '*', 'b', '**', 'c'], '']);
|
|
52
54
|
assert.deepStrictEqual(inspect(parser('**a*b***')), [['<strong>a<em>b</em></strong>'], '']);
|
|
@@ -61,41 +63,13 @@ describe('Unit: parser/inline', () => {
|
|
|
61
63
|
assert.deepStrictEqual(inspect(parser('**a **b****c')), [['<strong>a <strong>b</strong></strong>', 'c'], '']);
|
|
62
64
|
assert.deepStrictEqual(inspect(parser('**a ***b*****')), [['<strong>a <em><strong>b</strong></em></strong>'], '']);
|
|
63
65
|
assert.deepStrictEqual(inspect(parser('**a ***b*****c')), [['<strong>a <em><strong>b</strong></em></strong>', 'c'], '']);
|
|
64
|
-
assert.deepStrictEqual(inspect(parser('***a*b**')), [['<strong><em>a</em>b</strong>'], '']);
|
|
65
|
-
assert.deepStrictEqual(inspect(parser('***a*b**c')), [['<strong><em>a</em>b</strong>', 'c'], '']);
|
|
66
|
-
assert.deepStrictEqual(inspect(parser('***a*b*c***')), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
|
|
67
|
-
assert.deepStrictEqual(inspect(parser('***a*b*c***d')), [['<strong><em>a</em>b<em>c</em></strong>', 'd'], '']);
|
|
68
|
-
assert.deepStrictEqual(inspect(parser('***a*b**c****')), [['<strong><em>a</em>b</strong>', 'c', '****'], '']);
|
|
69
|
-
assert.deepStrictEqual(inspect(parser('***a* **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
|
|
70
|
-
assert.deepStrictEqual(inspect(parser('***a*\\ **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
|
|
71
|
-
assert.deepStrictEqual(inspect(parser('***a*	**b****')), [['<strong><em>a</em>\t<strong>b</strong></strong>'], '']);
|
|
72
|
-
assert.deepStrictEqual(inspect(parser('***a*<wbr>**b****')), [['<strong><em>a</em><wbr><strong>b</strong></strong>'], '']);
|
|
73
|
-
assert.deepStrictEqual(inspect(parser('***a *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
|
|
74
|
-
assert.deepStrictEqual(inspect(parser('***a\\ *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
|
|
75
|
-
assert.deepStrictEqual(inspect(parser('***a	*b****')), [['<em><strong>a\t<em>b</em></strong></em>'], '']);
|
|
76
|
-
assert.deepStrictEqual(inspect(parser('***a<wbr>*b****')), [['<em><strong>a<wbr><em>b</em></strong></em>'], '']);
|
|
77
|
-
assert.deepStrictEqual(inspect(parser('***a*b **')), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
|
|
78
|
-
assert.deepStrictEqual(inspect(parser('***a*b\\ **')), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
|
|
79
|
-
assert.deepStrictEqual(inspect(parser('***a**b*')), [['<em><strong>a</strong>b</em>'], '']);
|
|
80
|
-
assert.deepStrictEqual(inspect(parser('***a**b*c')), [['<em><strong>a</strong>b</em>', 'c'], '']);
|
|
81
|
-
assert.deepStrictEqual(inspect(parser('***a**b*c**')), [['<em><strong>a</strong>b</em>', 'c', '**'], '']);
|
|
82
|
-
assert.deepStrictEqual(inspect(parser('***a**b**c***')), [['<em><strong>a</strong>b<strong>c</strong></em>'], '']);
|
|
83
|
-
assert.deepStrictEqual(inspect(parser('***a**b**c***d')), [['<em><strong>a</strong>b<strong>c</strong></em>', 'd'], '']);
|
|
84
|
-
assert.deepStrictEqual(inspect(parser('***a** *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
|
|
85
|
-
assert.deepStrictEqual(inspect(parser('***a**\\ *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
|
|
86
|
-
assert.deepStrictEqual(inspect(parser('***a**	*b**')), [['<em><strong>a</strong>\t<em>b</em></em>'], '']);
|
|
87
|
-
assert.deepStrictEqual(inspect(parser('***a**<wbr>*b**')), [['<em><strong>a</strong><wbr><em>b</em></em>'], '']);
|
|
88
|
-
assert.deepStrictEqual(inspect(parser('***a **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
|
|
89
|
-
assert.deepStrictEqual(inspect(parser('***a\\ **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
|
|
90
|
-
assert.deepStrictEqual(inspect(parser('***a**b *')), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
|
|
91
|
-
assert.deepStrictEqual(inspect(parser('***a**b\\ *')), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
|
|
92
66
|
assert.deepStrictEqual(inspect(parser('***a*')), [['**', '<em>a</em>'], '']);
|
|
93
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
94
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
95
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
96
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
97
|
-
assert.deepStrictEqual(inspect(parser('
|
|
98
|
-
assert.deepStrictEqual(inspect(parser('
|
|
67
|
+
assert.deepStrictEqual(inspect(parser('***a*b')), [['**', '<em>a</em>', 'b'], '']);
|
|
68
|
+
assert.deepStrictEqual(inspect(parser('***a*b*')), [['**', '<em>a</em>', 'b', '*'], '']);
|
|
69
|
+
assert.deepStrictEqual(inspect(parser('***a*b*c')), [['**', '<em>a</em>', 'b', '*', 'c'], '']);
|
|
70
|
+
assert.deepStrictEqual(inspect(parser('***a*b*c*')), [['**', '<em>a</em>', 'b', '<em>c</em>'], '']);
|
|
71
|
+
assert.deepStrictEqual(inspect(parser('***a*b*c**')), [['**', '<em>a</em>', 'b', '<em>c</em>', '*'], '']);
|
|
72
|
+
assert.deepStrictEqual(inspect(parser('***a*b*c***')), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
|
|
99
73
|
assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
|
|
100
74
|
assert.deepStrictEqual(inspect(parser('**(**a**)**')), [['<strong><span class="paren">(<strong>a</strong>)</span></strong>'], '']);
|
|
101
75
|
assert.deepStrictEqual(inspect(parser('*++ ++*')), [['<em><ins> </ins></em>'], '']);
|
|
@@ -201,7 +175,7 @@ describe('Unit: parser/inline', () => {
|
|
|
201
175
|
assert.deepStrictEqual(inspect(parser('*a@b*')), [['<em><a class="email" href="mailto:a@b">a@b</a></em>'], '']);
|
|
202
176
|
assert.deepStrictEqual(inspect(parser('(a@b)')), [['<span class="paren">(<a class="email" href="mailto:a@b">a@b</a>)</span>'], '']);
|
|
203
177
|
assert.deepStrictEqual(inspect(parser(' a@b')), [[' ', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
204
|
-
assert.deepStrictEqual(inspect(parser('++a++b@c++')), [['<ins>a</ins>', '<a class="email" href="mailto:b@c">b@c</a>', '
|
|
178
|
+
assert.deepStrictEqual(inspect(parser('++a++b@c++')), [['<ins>a</ins>', '<a class="email" href="mailto:b@c">b@c</a>', '+', '+'], '']);
|
|
205
179
|
});
|
|
206
180
|
|
|
207
181
|
it('channel', () => {
|
package/src/parser/inline.ts
CHANGED
|
@@ -5,8 +5,8 @@ import { reference } from './inline/reference';
|
|
|
5
5
|
import { template } from './inline/template';
|
|
6
6
|
import { remark } from './inline/remark';
|
|
7
7
|
import { extension } from './inline/extension';
|
|
8
|
-
import { ruby } from './inline/ruby';
|
|
9
8
|
import { textlink } from './inline/link';
|
|
9
|
+
import { ruby } from './inline/ruby';
|
|
10
10
|
import { html } from './inline/html';
|
|
11
11
|
import { insertion } from './inline/insertion';
|
|
12
12
|
import { deletion } from './inline/deletion';
|
|
@@ -14,6 +14,7 @@ import { mark } from './inline/mark';
|
|
|
14
14
|
import { emstrong } from './inline/emstrong';
|
|
15
15
|
import { strong } from './inline/strong';
|
|
16
16
|
import { emphasis } from './inline/emphasis';
|
|
17
|
+
import { italic } from './inline/italic';
|
|
17
18
|
import { math } from './inline/math';
|
|
18
19
|
import { code } from './inline/code';
|
|
19
20
|
import { htmlentity } from './inline/htmlentity';
|
|
@@ -27,8 +28,8 @@ export import ReferenceParser = InlineParser.ReferenceParser;
|
|
|
27
28
|
export import TemplateParser = InlineParser.TemplateParser;
|
|
28
29
|
export import RemarkParser = InlineParser.RemarkParser;
|
|
29
30
|
export import ExtensionParser = InlineParser.ExtensionParser;
|
|
30
|
-
export import RubyParser = InlineParser.RubyParser;
|
|
31
31
|
export import LinkParser = InlineParser.LinkParser;
|
|
32
|
+
export import RubyParser = InlineParser.RubyParser;
|
|
32
33
|
export import HTMLParser = InlineParser.HTMLParser;
|
|
33
34
|
export import InsertionParser = InlineParser.InsertionParser;
|
|
34
35
|
export import DeletionParser = InlineParser.DeletionParser;
|
|
@@ -36,6 +37,7 @@ export import MarkParser = InlineParser.MarkParser;
|
|
|
36
37
|
export import EmStrongParser = InlineParser.EmStrongParser;
|
|
37
38
|
export import StrongParser = InlineParser.StrongParser;
|
|
38
39
|
export import EmphasisParser = InlineParser.EmphasisParser;
|
|
40
|
+
export import ItalicParser = InlineParser.ItalicParser;
|
|
39
41
|
export import MathParser = InlineParser.MathParser;
|
|
40
42
|
export import CodeParser = InlineParser.CodeParser;
|
|
41
43
|
export import MediaParser = InlineParser.MediaParser;
|
|
@@ -75,11 +77,13 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
75
77
|
return deletion(input);
|
|
76
78
|
case '==':
|
|
77
79
|
return mark(input);
|
|
80
|
+
case '//':
|
|
81
|
+
return italic(input);
|
|
78
82
|
}
|
|
79
83
|
switch (source[0]) {
|
|
80
84
|
case '[':
|
|
81
|
-
return
|
|
82
|
-
||
|
|
85
|
+
return textlink(input)
|
|
86
|
+
|| ruby(input);
|
|
83
87
|
case '{':
|
|
84
88
|
return textlink(input);
|
|
85
89
|
case '<':
|
|
@@ -34,9 +34,6 @@ export const text: TextParser = creation(1, Recursion.ignore, ({ source, context
|
|
|
34
34
|
case '\n':
|
|
35
35
|
return [[html('br')], source.slice(1)];
|
|
36
36
|
case '*':
|
|
37
|
-
case '+':
|
|
38
|
-
case '~':
|
|
39
|
-
case '=':
|
|
40
37
|
case '`':
|
|
41
38
|
return source[1] === source[0]
|
|
42
39
|
? repeat({ source, context })
|
package/src/parser/util.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { min } from 'spica/alias';
|
|
2
|
+
import { Command } from './context';
|
|
3
|
+
import { Parser, Result, Ctx, Tree, Context, eval, exec } from '../combinator/data/parser';
|
|
2
4
|
import { convert } from '../combinator';
|
|
3
5
|
import { define } from 'typed-dom/dom';
|
|
4
6
|
|
|
@@ -7,6 +9,69 @@ export function lineable<T extends HTMLElement | string>(parser: Parser<T>): Par
|
|
|
7
9
|
return convert(source => `\r${source}`, parser);
|
|
8
10
|
}
|
|
9
11
|
|
|
12
|
+
export function repeat<P extends Parser<HTMLElement | string>>(symbol: string, parser: P, cons: (nodes: Tree<P>[], context: Context<P>) => Tree<P>[], termination?: (acc: Tree<P>[][], rest: string, prefix: number, postfix: number, state: boolean) => Result<string | Tree<P>>): P;
|
|
13
|
+
export function repeat<T extends HTMLElement | string>(symbol: string, parser: Parser<T>, cons: (nodes: T[], context: Ctx) => T[], termination: (acc: T[][], rest: string, prefix: number, postfix: number, state: boolean) => Result<string | T> = (acc, rest, prefix, postfix) => {
|
|
14
|
+
const nodes = [];
|
|
15
|
+
if (prefix > 0) {
|
|
16
|
+
nodes.push(symbol[0].repeat(prefix));
|
|
17
|
+
}
|
|
18
|
+
for (let i = 0; i < acc.length; ++i) {
|
|
19
|
+
nodes.push(...acc[i]);
|
|
20
|
+
}
|
|
21
|
+
if (postfix > 0) {
|
|
22
|
+
nodes.push(rest.slice(0, postfix));
|
|
23
|
+
rest = rest.slice(postfix);
|
|
24
|
+
}
|
|
25
|
+
return [nodes, rest];
|
|
26
|
+
}): Parser<string | T> {
|
|
27
|
+
return input => {
|
|
28
|
+
const { source, context } = input;
|
|
29
|
+
assert(source.startsWith(symbol));
|
|
30
|
+
let acc: T[][] = [];
|
|
31
|
+
let i = symbol.length;
|
|
32
|
+
while (source[i] === source[0]) ++i;
|
|
33
|
+
let rest = source.slice(i);
|
|
34
|
+
let state = false;
|
|
35
|
+
for (; i >= symbol.length; i -= symbol.length) {
|
|
36
|
+
if (acc.length > 0 && rest.startsWith(symbol)) {
|
|
37
|
+
acc = [cons(acc.flat(), context)];
|
|
38
|
+
rest = rest.slice(symbol.length);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const result = parser({ source: rest, context });
|
|
42
|
+
if (result === undefined) break;
|
|
43
|
+
const nodes = eval(result);
|
|
44
|
+
rest = exec(result);
|
|
45
|
+
acc.push(nodes);
|
|
46
|
+
switch (nodes.at(-1)) {
|
|
47
|
+
case Command.Escape:
|
|
48
|
+
assert(!rest.startsWith(symbol));
|
|
49
|
+
nodes.pop();
|
|
50
|
+
state = false;
|
|
51
|
+
break;
|
|
52
|
+
case Command.Separator:
|
|
53
|
+
assert(!rest.startsWith(symbol));
|
|
54
|
+
nodes.pop();
|
|
55
|
+
state = true;
|
|
56
|
+
continue;
|
|
57
|
+
default:
|
|
58
|
+
acc = [cons(acc.flat(), context)];
|
|
59
|
+
state = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (acc.length === 0) return;
|
|
65
|
+
const prefix = i;
|
|
66
|
+
i = 0;
|
|
67
|
+
for (let len = min(prefix, rest.length); i < len && rest[i] === symbol[0];) {
|
|
68
|
+
++i;
|
|
69
|
+
}
|
|
70
|
+
const postfix = i;
|
|
71
|
+
return termination(acc, rest, prefix, postfix, state);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
10
75
|
export function markInvalid<T extends Element>(
|
|
11
76
|
el: T,
|
|
12
77
|
syntax: string,
|
package/src/parser/visibility.ts
CHANGED
|
@@ -45,36 +45,39 @@ function hasVisible(
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export function blankWith(delimiter: string | RegExp): RegExp;
|
|
48
|
-
export function blankWith(
|
|
49
|
-
export function blankWith(
|
|
50
|
-
if (delimiter === undefined) return blankWith('',
|
|
48
|
+
export function blankWith(starts: '' | '\n', delimiter: string | RegExp): RegExp;
|
|
49
|
+
export function blankWith(starts: '' | '\n', delimiter?: string | RegExp): RegExp {
|
|
50
|
+
if (delimiter === undefined) return blankWith('', starts);
|
|
51
51
|
return new RegExp(String.raw
|
|
52
|
-
`^(?:(?=${
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
`^(?:(?=${starts})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr[^\S\n]*>)${
|
|
53
|
+
// 空行除去
|
|
54
|
+
starts && '+'
|
|
55
|
+
})?${
|
|
56
|
+
typeof delimiter === 'string'
|
|
57
|
+
? delimiter.replace(/[*+()\[\]]/g, '\\$&')
|
|
58
|
+
: delimiter.source
|
|
56
59
|
}`);
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
//export function
|
|
60
|
-
//export function
|
|
62
|
+
//export function looseStart<P extends Parser<HTMLElement | string>>(parser: P, except?: string): P;
|
|
63
|
+
//export function looseStart<T extends HTMLElement | string>(parser: Parser<T>, except?: string): Parser<T> {
|
|
61
64
|
// return input =>
|
|
62
|
-
//
|
|
65
|
+
// isLooseStart(input, except)
|
|
63
66
|
// ? parser(input)
|
|
64
67
|
// : undefined;
|
|
65
68
|
//}
|
|
66
|
-
//const
|
|
67
|
-
// return
|
|
69
|
+
//const isLooseStart = reduce(({ source, context }: Input<MarkdownParser.Context>, except?: string): boolean => {
|
|
70
|
+
// return isTightStart({ source: source.replace(blank.start, ''), context }, except);
|
|
68
71
|
//}, ({ source }, except = '') => `${source}${Command.Separator}${except}`);
|
|
69
72
|
|
|
70
|
-
export function
|
|
71
|
-
export function
|
|
73
|
+
export function tightStart<P extends Parser<unknown>>(parser: P, except?: string): P;
|
|
74
|
+
export function tightStart<T>(parser: Parser<T>, except?: string): Parser<T> {
|
|
72
75
|
return input =>
|
|
73
|
-
|
|
76
|
+
isTightStart(input, except)
|
|
74
77
|
? parser(input)
|
|
75
78
|
: undefined;
|
|
76
79
|
}
|
|
77
|
-
const
|
|
80
|
+
const isTightStart = reduce((input: Input<MarkdownParser.Context>, except?: string): boolean => {
|
|
78
81
|
const { source } = input;
|
|
79
82
|
if (source === '') return true;
|
|
80
83
|
if (except && source.slice(0, except.length) === except) return false;
|
|
@@ -107,7 +110,7 @@ const isStartTight = reduce((input: Input<MarkdownParser.Context>, except?: stri
|
|
|
107
110
|
}
|
|
108
111
|
}, ({ source }, except = '') => `${source}${Command.Separator}${except}`);
|
|
109
112
|
|
|
110
|
-
export function
|
|
113
|
+
export function isLooseNodeStart(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
111
114
|
if (nodes.length === 0) return true;
|
|
112
115
|
for (let i = 0; i < nodes.length; ++i) {
|
|
113
116
|
const node = nodes[i];
|
|
@@ -116,11 +119,11 @@ export function isStartLooseNodes(nodes: readonly (HTMLElement | string)[]): boo
|
|
|
116
119
|
}
|
|
117
120
|
return false;
|
|
118
121
|
}
|
|
119
|
-
export function
|
|
122
|
+
export function isTightNodeStart(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
120
123
|
if (nodes.length === 0) return true;
|
|
121
124
|
return isVisible(nodes[0], 0);
|
|
122
125
|
}
|
|
123
|
-
//export function
|
|
126
|
+
//export function isTightNodeEnd(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
124
127
|
// if (nodes.length === 0) return true;
|
|
125
128
|
// return isVisible(nodes.at(-1)!, -1);
|
|
126
129
|
//}
|