securemark 0.234.1 → 0.235.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 +12 -0
- package/dist/securemark.js +128 -136
- package/markdown.d.ts +4 -16
- package/package-lock.json +46 -43
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.ts +0 -2
- package/src/combinator/control/constraint/contract.ts +1 -1
- package/src/combinator/control/manipulation/context.ts +7 -0
- package/src/combinator/control/manipulation/match.ts +1 -1
- package/src/combinator/control/manipulation/scope.ts +1 -1
- package/src/combinator/data/parser/inits.ts +1 -1
- package/src/combinator/data/parser/sequence.ts +1 -1
- package/src/combinator/data/parser/some.ts +40 -18
- package/src/combinator/data/parser.ts +4 -1
- package/src/parser/api/normalize.ts +7 -6
- package/src/parser/block/heading.test.ts +1 -1
- package/src/parser/block/paragraph.test.ts +2 -0
- package/src/parser/inline/emphasis.test.ts +7 -4
- package/src/parser/inline/emphasis.ts +7 -7
- package/src/parser/inline/emstrong.ts +19 -18
- package/src/parser/inline/extension/index.test.ts +19 -18
- package/src/parser/inline/extension/index.ts +3 -4
- package/src/parser/inline/extension/indexer.test.ts +1 -0
- package/src/parser/inline/extension/indexer.ts +1 -0
- package/src/parser/inline/html.ts +4 -8
- package/src/parser/inline/htmlentity.test.ts +1 -0
- package/src/parser/inline/htmlentity.ts +9 -12
- package/src/parser/inline/link.ts +3 -4
- package/src/parser/inline/mark.test.ts +6 -3
- package/src/parser/inline/mark.ts +4 -4
- package/src/parser/inline/media.ts +8 -5
- package/src/parser/inline/ruby.ts +3 -4
- package/src/parser/inline/strong.test.ts +6 -4
- package/src/parser/inline/strong.ts +7 -7
- package/src/parser/inline.test.ts +15 -5
- package/src/parser/util.ts +11 -42
|
@@ -20,13 +20,19 @@ describe('Unit: parser/inline/extension/index', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('[#\\]')), undefined);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('[#a')), undefined);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('[#*a\nb*]')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('[#a\n|#b]')), undefined);
|
|
23
24
|
assert.deepStrictEqual(inspect(parser('[#a|#\n]')), undefined);
|
|
24
25
|
assert.deepStrictEqual(inspect(parser('[#a|#\\\n]')), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('[#a|#(\n)]')), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser('[#a|#(\\\n)]')), undefined);
|
|
25
28
|
assert.deepStrictEqual(inspect(parser('[# |]')), undefined);
|
|
26
29
|
assert.deepStrictEqual(inspect(parser('[# |#]')), undefined);
|
|
27
30
|
assert.deepStrictEqual(inspect(parser('[# |#b]')), undefined);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('[#
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('[# |#
|
|
31
|
+
assert.deepStrictEqual(inspect(parser('[# a|]')), undefined);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('[# a|#]')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('[# a|#b]')), undefined);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('[# a|# ]')), undefined);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('[# a|# b]')), undefined);
|
|
30
36
|
assert.deepStrictEqual(inspect(parser(' [#a]')), undefined);
|
|
31
37
|
});
|
|
32
38
|
|
|
@@ -64,26 +70,21 @@ describe('Unit: parser/inline/extension/index', () => {
|
|
|
64
70
|
assert.deepStrictEqual(inspect(parser('[#|]')), [['<a class="index" href="#index:|">|</a>'], '']);
|
|
65
71
|
assert.deepStrictEqual(inspect(parser('[#|#]')), [['<a class="index" href="#index:|#">|#</a>'], '']);
|
|
66
72
|
assert.deepStrictEqual(inspect(parser('[#|#b]')), [['<a class="index" href="#index:|#b">|#b</a>'], '']);
|
|
67
|
-
assert.deepStrictEqual(inspect(parser('[#a
|
|
68
|
-
assert.deepStrictEqual(inspect(parser('[#a|#]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
|
|
69
|
-
assert.deepStrictEqual(inspect(parser('[#a|# ]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
|
|
70
|
-
assert.deepStrictEqual(inspect(parser('[#a|#\\ ]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
|
|
71
|
-
assert.deepStrictEqual(inspect(parser('[#a|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
72
|
-
assert.deepStrictEqual(inspect(parser('[#a|#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
73
|
-
assert.deepStrictEqual(inspect(parser('[#a|#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
74
|
-
assert.deepStrictEqual(inspect(parser('[#a|#\\b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
75
|
-
assert.deepStrictEqual(inspect(parser('[#a|#*b*]')), [['<a class="index" href="#index:*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
|
|
76
|
-
assert.deepStrictEqual(inspect(parser('[#a|#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
|
|
77
|
-
assert.deepStrictEqual(inspect(parser('[#a|#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
|
|
78
|
-
assert.deepStrictEqual(inspect(parser('[#a|#[]]')), [['<a class="index" href="#index:[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
|
|
79
|
-
assert.deepStrictEqual(inspect(parser('[#a|#©]')), [['<a class="index" href="#index:&copy;">a<span class="indexer" data-index="&copy;"></span></a>'], '']);
|
|
73
|
+
assert.deepStrictEqual(inspect(parser('[#a|#b]')), [['<a class="index" href="#index:a|#b">a|#b</a>'], '']);
|
|
80
74
|
assert.deepStrictEqual(inspect(parser('[#a |]')), [['<a class="index" href="#index:a_|">a |</a>'], '']);
|
|
81
75
|
assert.deepStrictEqual(inspect(parser('[#a |#]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
|
|
76
|
+
assert.deepStrictEqual(inspect(parser('[#a |# ]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
|
|
77
|
+
assert.deepStrictEqual(inspect(parser('[#a |#\\ ]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
|
|
82
78
|
assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
79
|
+
assert.deepStrictEqual(inspect(parser('[#a |#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
80
|
+
assert.deepStrictEqual(inspect(parser('[#a |#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
81
|
+
assert.deepStrictEqual(inspect(parser('[#a |#\\b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
82
|
+
assert.deepStrictEqual(inspect(parser('[#a |#*b*]')), [['<a class="index" href="#index:*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
|
|
83
|
+
assert.deepStrictEqual(inspect(parser('[#a |#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
|
|
84
|
+
assert.deepStrictEqual(inspect(parser('[#a |#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('[#a |#[]]')), [['<a class="index" href="#index:[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser('[#a |#©]')), [['<a class="index" href="#index:&copy;">a<span class="indexer" data-index="&copy;"></span></a>'], '']);
|
|
83
87
|
assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
84
|
-
assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
85
|
-
assert.deepStrictEqual(inspect(parser('[#a <wbr>|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
|
|
86
|
-
assert.deepStrictEqual(inspect(parser('[#a [# b #]|#b]')), [['<a class="index" href="#index:b">a <span class="comment"><input type="checkbox"><span>[# b #]</span></span><span class="indexer" data-index="b"></span></a>'], '']);
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
});
|
|
@@ -23,11 +23,10 @@ export const index: IndexParser = lazy(() => creator(validate('[#', ']', '\n', f
|
|
|
23
23
|
media: false,
|
|
24
24
|
autolink: false,
|
|
25
25
|
}}},
|
|
26
|
-
open(str(/^\|?/, false),
|
|
27
26
|
some(union([
|
|
28
27
|
signature,
|
|
29
28
|
inline,
|
|
30
|
-
]), ']', /^\\?\n/)
|
|
29
|
+
]), ']', /^\\?\n/)))),
|
|
31
30
|
']'),
|
|
32
31
|
ns => [html('a', trimNodeEnd(defrag(ns)))])),
|
|
33
32
|
([el]: [HTMLAnchorElement]) => [
|
|
@@ -41,8 +40,8 @@ export const index: IndexParser = lazy(() => creator(validate('[#', ']', '\n', f
|
|
|
41
40
|
]))));
|
|
42
41
|
|
|
43
42
|
const signature: IndexParser.SignatureParser = lazy(() => creator(fmap(open(
|
|
44
|
-
|
|
45
|
-
startTight(some(union([bracket, txt]), ']'
|
|
43
|
+
/^\s+\|#/,
|
|
44
|
+
startTight(some(union([bracket, txt]), ']'))),
|
|
46
45
|
ns => [
|
|
47
46
|
html('span', { class: 'indexer', 'data-index': identity(join(ns)).slice(6) }),
|
|
48
47
|
])));
|
|
@@ -15,6 +15,7 @@ describe('Unit: parser/inline/extension/indexer', () => {
|
|
|
15
15
|
assert.deepStrictEqual(inspect(parser(' [#]')), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser(' [#]]')), undefined);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser(' [#a]]')), undefined);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser(' [#&a;]')), undefined);
|
|
18
19
|
});
|
|
19
20
|
|
|
20
21
|
it('valid', () => {
|
|
@@ -10,6 +10,7 @@ export const indexer: ExtensionParser.IndexerParser = creator(fmap(verify(surrou
|
|
|
10
10
|
}}},
|
|
11
11
|
union([index])),
|
|
12
12
|
/^\s*$/),
|
|
13
|
+
// Indexer is invisible but invalids must be visible.
|
|
13
14
|
([el]) => el.getElementsByClassName('invalid').length === 0),
|
|
14
15
|
([el]) => [
|
|
15
16
|
html('span', { class: 'indexer', 'data-index': el.getAttribute('href')!.slice(7) }),
|
|
@@ -26,11 +26,9 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
26
26
|
memoize(
|
|
27
27
|
([, tag]) =>
|
|
28
28
|
surround(
|
|
29
|
-
|
|
30
|
-
([,
|
|
31
|
-
[h(tag as 'span', attributes('html', [], attrspec[tag],
|
|
32
|
-
rest
|
|
33
|
-
]),
|
|
29
|
+
`<${tag}`, some(union([attribute])), '>', true,
|
|
30
|
+
([, bs = []], rest) =>
|
|
31
|
+
[[h(tag as 'span', attributes('html', [], attrspec[tag], bs))], rest]),
|
|
34
32
|
([, tag]) => tag)),
|
|
35
33
|
match(
|
|
36
34
|
/^(?=<(sup|sub|small|bdo|bdi)(?=[^\S\n]|>))/,
|
|
@@ -80,9 +78,7 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
80
78
|
([as, bs, cs], rest) =>
|
|
81
79
|
[[elem(tag, as, trimNodeEndBR(defrag(bs)), cs, {})], rest],
|
|
82
80
|
([as, bs], rest) =>
|
|
83
|
-
as.length === 1
|
|
84
|
-
? [unshift(as, bs), rest]
|
|
85
|
-
: undefined)),
|
|
81
|
+
as.length === 1 ? [unshift(as, bs), rest] : undefined)),
|
|
86
82
|
([, tag]) => tag,
|
|
87
83
|
new Cache(1000))),
|
|
88
84
|
])))));
|
|
@@ -14,6 +14,7 @@ describe('Unit: parser/inline/htmlentity', () => {
|
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('& ;')), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('&\n;')), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('&a;')), [['<span class="invalid">&a;</span>'], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser('
')), undefined);
|
|
17
18
|
assert.deepStrictEqual(inspect(parser('&#;')), undefined);
|
|
18
19
|
assert.deepStrictEqual(inspect(parser('&#g;')), undefined);
|
|
19
20
|
assert.deepStrictEqual(inspect(parser('&#x;')), undefined);
|
|
@@ -2,18 +2,15 @@ import { HTMLEntityParser, UnsafeHTMLEntityParser } from '../inline';
|
|
|
2
2
|
import { union, validate, focus, creator, fmap } from '../../combinator';
|
|
3
3
|
import { html } from 'typed-dom';
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
export const unsafehtmlentity: UnsafeHTMLEntityParser = creator(validate('&', focus(
|
|
6
|
+
/^&(?!NewLine;)[0-9A-Za-z]+;/,
|
|
7
|
+
(parser => entity => (
|
|
8
|
+
parser.innerHTML = entity,
|
|
9
|
+
entity = parser.textContent!,
|
|
10
|
+
[[`${entity[0] !== '&' || entity.length === 1 ? '' : '\0'}${entity}`], '']
|
|
11
|
+
))(html('b')))));
|
|
6
12
|
|
|
7
|
-
export const
|
|
8
|
-
/^&[0-9A-Za-z]+;/,
|
|
9
|
-
entity => [[(parser.innerHTML = entity, parser.value)], '']),
|
|
10
|
-
([str]) => [
|
|
11
|
-
str[0] !== '&' || str.length < 3
|
|
12
|
-
? str
|
|
13
|
-
: `\0${str}`,
|
|
14
|
-
])));
|
|
15
|
-
|
|
16
|
-
export const htmlentity: HTMLEntityParser = creator(validate('&', fmap(
|
|
13
|
+
export const htmlentity: HTMLEntityParser = fmap(
|
|
17
14
|
union([unsafehtmlentity]),
|
|
18
15
|
([str]) => [
|
|
19
16
|
str[0] === '\0'
|
|
@@ -24,4 +21,4 @@ export const htmlentity: HTMLEntityParser = creator(validate('&', fmap(
|
|
|
24
21
|
'data-invalid-description': 'Invalid HTML entity.',
|
|
25
22
|
}, str.slice(1))
|
|
26
23
|
: str,
|
|
27
|
-
])
|
|
24
|
+
]);
|
|
@@ -16,8 +16,7 @@ const optspec = {
|
|
|
16
16
|
} as const;
|
|
17
17
|
ObjectSetPrototypeOf(optspec, null);
|
|
18
18
|
|
|
19
|
-
export const link: LinkParser = lazy(() => creator(10, bind(
|
|
20
|
-
validate(['[', '{'], '}', '\n',
|
|
19
|
+
export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}', '\n', bind(
|
|
21
20
|
guard(context => context.syntax?.inline?.link ?? true,
|
|
22
21
|
reverse(tails([
|
|
23
22
|
context({ syntax: { inline: {
|
|
@@ -44,7 +43,7 @@ export const link: LinkParser = lazy(() => creator(10, bind(
|
|
|
44
43
|
true),
|
|
45
44
|
]))),
|
|
46
45
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
|
|
47
|
-
])))
|
|
46
|
+
]))),
|
|
48
47
|
([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
|
|
49
48
|
assert(params.every(p => typeof p === 'string'));
|
|
50
49
|
if (eval(some(autolink)(stringify(content), context))?.some(node => typeof node === 'object')) return;
|
|
@@ -62,7 +61,7 @@ export const link: LinkParser = lazy(() => creator(10, bind(
|
|
|
62
61
|
if (el.classList.contains('invalid')) return [[el], rest];
|
|
63
62
|
assert(el.classList.length === 0);
|
|
64
63
|
return [[define(el, attributes('link', [], optspec, params))], rest];
|
|
65
|
-
})));
|
|
64
|
+
}))));
|
|
66
65
|
|
|
67
66
|
export const uri: LinkParser.ParameterParser.UriParser = union([
|
|
68
67
|
open(/^[^\S\n]/, str(/^\S+/)),
|
|
@@ -14,8 +14,8 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('==a=')), [['==', 'a', '='], '']);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' ', '=='], '']);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a', '<br>', '=='], '']);
|
|
17
|
-
assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a', ' '
|
|
18
|
-
assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a', '<span class="linebreak"> </span>'
|
|
17
|
+
assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a', ' ', '=='], '']);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a', '<span class="linebreak"> </span>', '=='], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('== ==')), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('== a==')), undefined);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('== a ==')), undefined);
|
|
@@ -35,8 +35,11 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('nest', () => {
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('==*==a==*==')), [['<mark><em><mark>a</mark></em></mark>'], '']);
|
|
39
38
|
assert.deepStrictEqual(inspect(parser('==a ==b====')), [['<mark>a <mark>b</mark></mark>'], '']);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser('==a\\ ==b====')), [['<mark>a <mark>b</mark></mark>'], '']);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('==a	==b====')), [['<mark>a\t<mark>b</mark></mark>'], '']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser('==a<wbr>==b====')), [['<mark>a<wbr><mark>b</mark></mark>'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('==*==a==*==')), [['<mark><em><mark>a</mark></em></mark>'], '']);
|
|
40
43
|
});
|
|
41
44
|
|
|
42
45
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { MarkParser } from '../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, some, creator, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
|
-
import { startTight, isEndTightNodes } from '../util';
|
|
5
|
+
import { startTight, isEndTightNodes, delimiter } from '../util';
|
|
6
6
|
import { html, defrag } from 'typed-dom';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
|
|
9
9
|
export const mark: MarkParser = lazy(() => creator(surround(
|
|
10
10
|
str('=='),
|
|
11
11
|
startTight(some(union([
|
|
12
|
-
some(inline,
|
|
13
|
-
|
|
12
|
+
some(inline, delimiter(/==/)),
|
|
13
|
+
open(some(inline, '='), inline),
|
|
14
14
|
]))),
|
|
15
15
|
str('=='), false,
|
|
16
16
|
([as, bs, cs], rest) =>
|
|
@@ -18,14 +18,17 @@ const optspec = {
|
|
|
18
18
|
} as const;
|
|
19
19
|
ObjectSetPrototypeOf(optspec, null);
|
|
20
20
|
|
|
21
|
-
export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
|
|
21
|
+
export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'], '}', '\n', bind(verify(fmap(open(
|
|
22
22
|
'!',
|
|
23
|
-
validate(['[', '{'], '}', '\n',
|
|
24
23
|
guard(context => context.syntax?.inline?.media ?? true,
|
|
25
24
|
tails([
|
|
26
|
-
dup(surround(
|
|
25
|
+
dup(surround(
|
|
26
|
+
/^\[(?!\s*\\\s)/,
|
|
27
|
+
some(union([unsafehtmlentity, bracket, txt]), ']', /^\\?\n/),
|
|
28
|
+
']',
|
|
29
|
+
true)),
|
|
27
30
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
|
|
28
|
-
])))
|
|
31
|
+
]))),
|
|
29
32
|
([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
|
|
30
33
|
([[text]]) => text === '' || text.trim() !== ''),
|
|
31
34
|
([[text], params], rest, context) => {
|
|
@@ -51,7 +54,7 @@ export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
|
|
|
51
54
|
link as MediaParser,
|
|
52
55
|
([link]) => [define(link, { target: '_blank' }, [el])])
|
|
53
56
|
(`{ ${INSECURE_URI}${join(params)} }${rest}`, context);
|
|
54
|
-
})));
|
|
57
|
+
}))));
|
|
55
58
|
|
|
56
59
|
const bracket: MediaParser.TextParser.BracketParser = lazy(() => union([
|
|
57
60
|
surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
@@ -8,12 +8,11 @@ import { isStartTightNodes } from '../util';
|
|
|
8
8
|
import { html, defrag } from 'typed-dom';
|
|
9
9
|
import { unshift, push, join } from 'spica/array';
|
|
10
10
|
|
|
11
|
-
export const ruby: RubyParser = lazy(() => creator(bind(verify(
|
|
12
|
-
validate('[', ')', '\n',
|
|
11
|
+
export const ruby: RubyParser = lazy(() => creator(validate('[', ')', '\n', bind(verify(
|
|
13
12
|
sequence([
|
|
14
13
|
surround('[', focus(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'),
|
|
15
14
|
surround('(', focus(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')'),
|
|
16
|
-
])
|
|
15
|
+
]),
|
|
17
16
|
([texts]) => isStartTightNodes(texts)),
|
|
18
17
|
([texts, rubies], rest) => {
|
|
19
18
|
const tail = typeof texts[texts.length - 1] === 'object'
|
|
@@ -44,7 +43,7 @@ export const ruby: RubyParser = lazy(() => creator(bind(verify(
|
|
|
44
43
|
[html('rp', '('), html('rt', join(rubies, ' ').trim()), html('rp', ')')]), tail)))
|
|
45
44
|
], rest];
|
|
46
45
|
}
|
|
47
|
-
})));
|
|
46
|
+
}))));
|
|
48
47
|
|
|
49
48
|
const text: RubyParser.TextParser = creator((source, context) => {
|
|
50
49
|
const acc = [''];
|
|
@@ -12,8 +12,8 @@ describe('Unit: parser/inline/strong', () => {
|
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' ', '**'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a', '<br>', '**'], '']);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' '
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>'
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' ', '**'], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>', '**'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('** **')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('** a**')), undefined);
|
|
@@ -35,10 +35,12 @@ describe('Unit: parser/inline/strong', () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('nest', () => {
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('**a*b*c**')), [['<strong>a<em>b</em>c</strong>'], '']);
|
|
39
|
-
assert.deepStrictEqual(inspect(parser('**a*b*c**d')), [['<strong>a<em>b</em>c</strong>'], 'd']);
|
|
40
38
|
assert.deepStrictEqual(inspect(parser('**a *b***')), [['<strong>a <em>b</em></strong>'], '']);
|
|
41
39
|
assert.deepStrictEqual(inspect(parser('**a **b****')), [['<strong>a <strong>b</strong></strong>'], '']);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('**a	**b****')), [['<strong>a\t<strong>b</strong></strong>'], '']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser('**a<wbr>**b****')), [['<strong>a<wbr><strong>b</strong></strong>'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('**a*b*c**')), [['<strong>a<em>b</em>c</strong>'], '']);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('**a*b*c**d')), [['<strong>a<em>b</em>c</strong>'], 'd']);
|
|
42
44
|
assert.deepStrictEqual(inspect(parser('**`a`**')), [['<strong><code data-src="`a`">a</code></strong>'], '']);
|
|
43
45
|
assert.deepStrictEqual(inspect(parser('**<small>**')), [['<strong><small></strong>'], '']);
|
|
44
46
|
assert.deepStrictEqual(inspect(parser('**(*a*)**')), [['<strong><span class="paren">(<em>a</em>)</span></strong>'], '']);
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { StrongParser } from '../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, some, creator, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { str } from '../source';
|
|
5
|
-
import { startTight, isEndTightNodes } from '../util';
|
|
5
|
+
import { startTight, isEndTightNodes, delimiter } from '../util';
|
|
6
6
|
import { html, defrag } from 'typed-dom';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
|
|
9
|
-
export const strong: StrongParser = lazy(() => creator(surround(
|
|
10
|
-
str('**'),
|
|
9
|
+
export const strong: StrongParser = lazy(() => creator(surround(
|
|
10
|
+
str('**'),
|
|
11
11
|
startTight(some(union([
|
|
12
|
-
some(inline,
|
|
13
|
-
|
|
14
|
-
]))),
|
|
12
|
+
some(inline, delimiter(/\*\*/)),
|
|
13
|
+
open(some(inline, '*'), inline),
|
|
14
|
+
])), '*'),
|
|
15
15
|
str('**'), false,
|
|
16
16
|
([as, bs, cs], rest) =>
|
|
17
17
|
isEndTightNodes(bs)
|
|
@@ -64,18 +64,28 @@ describe('Unit: parser/inline', () => {
|
|
|
64
64
|
assert.deepStrictEqual(inspect(parser('***a*b*c***')), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
|
|
65
65
|
assert.deepStrictEqual(inspect(parser('***a*b*c***d')), [['<strong><em>a</em>b<em>c</em></strong>', 'd'], '']);
|
|
66
66
|
assert.deepStrictEqual(inspect(parser('***a*b**c****')), [['<strong><em>a</em>b</strong>', 'c', '****'], '']);
|
|
67
|
-
assert.deepStrictEqual(inspect(parser('***a*b
|
|
68
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
67
|
+
assert.deepStrictEqual(inspect(parser('***a* **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
|
|
68
|
+
assert.deepStrictEqual(inspect(parser('***a*\\ **b****')), [['<strong><em>a</em> <strong>b</strong></strong>'], '']);
|
|
69
|
+
assert.deepStrictEqual(inspect(parser('***a*	**b****')), [['<strong><em>a</em>\t<strong>b</strong></strong>'], '']);
|
|
70
|
+
assert.deepStrictEqual(inspect(parser('***a*<wbr>**b****')), [['<strong><em>a</em><wbr><strong>b</strong></strong>'], '']);
|
|
71
|
+
assert.deepStrictEqual(inspect(parser('***a *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
|
|
72
|
+
assert.deepStrictEqual(inspect(parser('***a\\ *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
|
|
73
|
+
assert.deepStrictEqual(inspect(parser('***a	*b****')), [['<em><strong>a\t<em>b</em></strong></em>'], '']);
|
|
74
|
+
assert.deepStrictEqual(inspect(parser('***a<wbr>*b****')), [['<em><strong>a<wbr><em>b</em></strong></em>'], '']);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('***a*b **')), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
|
|
69
76
|
assert.deepStrictEqual(inspect(parser('***a*b\\ **')), [['**', '<em>a</em>', 'b', ' ', '**'], '']);
|
|
70
|
-
assert.deepStrictEqual(inspect(parser('***a* b**')), [['<strong><em>a</em> b</strong>'], '']);
|
|
71
77
|
assert.deepStrictEqual(inspect(parser('***a**b*')), [['<em><strong>a</strong>b</em>'], '']);
|
|
72
78
|
assert.deepStrictEqual(inspect(parser('***a**b*c')), [['<em><strong>a</strong>b</em>', 'c'], '']);
|
|
73
79
|
assert.deepStrictEqual(inspect(parser('***a**b*c**')), [['<em><strong>a</strong>b</em>', 'c', '**'], '']);
|
|
74
80
|
assert.deepStrictEqual(inspect(parser('***a**b**c***')), [['<em><strong>a</strong>b<strong>c</strong></em>'], '']);
|
|
75
81
|
assert.deepStrictEqual(inspect(parser('***a**b**c***d')), [['<em><strong>a</strong>b<strong>c</strong></em>', 'd'], '']);
|
|
76
|
-
assert.deepStrictEqual(inspect(parser('***a**b
|
|
77
|
-
assert.deepStrictEqual(inspect(parser('***a
|
|
82
|
+
assert.deepStrictEqual(inspect(parser('***a** *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
|
|
83
|
+
assert.deepStrictEqual(inspect(parser('***a**\\ *b**')), [['<em><strong>a</strong> <em>b</em></em>'], '']);
|
|
84
|
+
assert.deepStrictEqual(inspect(parser('***a**	*b**')), [['<em><strong>a</strong>\t<em>b</em></em>'], '']);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('***a**<wbr>*b**')), [['<em><strong>a</strong><wbr><em>b</em></em>'], '']);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser('***a **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
|
|
78
87
|
assert.deepStrictEqual(inspect(parser('***a\\ **b*')), [['***', 'a', ' ', '**', 'b', '*'], '']);
|
|
88
|
+
assert.deepStrictEqual(inspect(parser('***a**b *')), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
|
|
79
89
|
assert.deepStrictEqual(inspect(parser('***a**b\\ *')), [['*', '<strong>a</strong>', 'b', ' ', '*'], '']);
|
|
80
90
|
assert.deepStrictEqual(inspect(parser('***a*')), [['**', '<em>a</em>'], '']);
|
|
81
91
|
assert.deepStrictEqual(inspect(parser('***a**')), [['*', '<strong>a</strong>'], '']);
|
package/src/parser/util.ts
CHANGED
|
@@ -4,47 +4,16 @@ import { Parser, eval } from '../combinator/data/parser';
|
|
|
4
4
|
import { union, some, verify, convert } from '../combinator';
|
|
5
5
|
import { unsafehtmlentity } from './inline/htmlentity';
|
|
6
6
|
import { linebreak, unescsource } from './source';
|
|
7
|
+
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
7
8
|
import { push, pop } from 'spica/array';
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'NewLine',
|
|
13
|
-
'NonBreakingSpace',
|
|
14
|
-
'nbsp',
|
|
15
|
-
'shy',
|
|
16
|
-
'ensp',
|
|
17
|
-
'emsp',
|
|
18
|
-
'emsp13',
|
|
19
|
-
'emsp14',
|
|
20
|
-
'numsp',
|
|
21
|
-
'puncsp',
|
|
22
|
-
'ThinSpace',
|
|
23
|
-
'thinsp',
|
|
24
|
-
'VeryThinSpace',
|
|
25
|
-
'hairsp',
|
|
26
|
-
'ZeroWidthSpace',
|
|
27
|
-
'NegativeVeryThinSpace',
|
|
28
|
-
'NegativeThinSpace',
|
|
29
|
-
'NegativeMediumSpace',
|
|
30
|
-
'NegativeThickSpace',
|
|
31
|
-
'zwj',
|
|
32
|
-
'zwnj',
|
|
33
|
-
'lrm',
|
|
34
|
-
'rlm',
|
|
35
|
-
'MediumSpace',
|
|
36
|
-
'NoBreak',
|
|
37
|
-
'ApplyFunction',
|
|
38
|
-
'af',
|
|
39
|
-
'InvisibleTimes',
|
|
40
|
-
'it',
|
|
41
|
-
'InvisibleComma',
|
|
42
|
-
'ic',
|
|
43
|
-
];
|
|
44
|
-
const blankline = new RegExp(String.raw`^(?!$)(?:\\$|\\?[^\S\n]|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)+$`, 'gm');
|
|
10
|
+
export function delimiter(opener: RegExp): RegExp {
|
|
11
|
+
return new RegExp(String.raw`^(?:\s+|\\\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)?${opener.source}`);
|
|
12
|
+
}
|
|
45
13
|
|
|
46
14
|
export function visualize<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
47
15
|
export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
16
|
+
const blankline = new RegExp(String.raw`^(?:\\$|\\?[^\S\n]|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)+$`, 'gm');
|
|
48
17
|
return union([
|
|
49
18
|
convert(
|
|
50
19
|
source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')),
|
|
@@ -79,18 +48,18 @@ export function startLoose<T extends HTMLElement | string>(parser: Parser<T>, ex
|
|
|
79
48
|
export function isStartLoose(source: string, context: MarkdownParser.Context, except?: string): boolean {
|
|
80
49
|
source &&= source.replace(/^[^\S\n]+/, '');
|
|
81
50
|
if (source === '') return true;
|
|
82
|
-
return source
|
|
83
|
-
&& isStartTight(source, context);
|
|
51
|
+
return isStartTight(source, context, except);
|
|
84
52
|
}
|
|
85
|
-
export function startTight<P extends Parser<unknown>>(parser: P): P;
|
|
86
|
-
export function startTight<T>(parser: Parser<T
|
|
53
|
+
export function startTight<P extends Parser<unknown>>(parser: P, except?: string): P;
|
|
54
|
+
export function startTight<T>(parser: Parser<T>, except?: string): Parser<T> {
|
|
87
55
|
return (source, context) =>
|
|
88
|
-
isStartTight(source, context)
|
|
56
|
+
isStartTight(source, context, except)
|
|
89
57
|
? parser(source, context)
|
|
90
58
|
: undefined;
|
|
91
59
|
}
|
|
92
|
-
function isStartTight(source: string, context: MarkdownParser.Context): boolean {
|
|
60
|
+
function isStartTight(source: string, context: MarkdownParser.Context, except?: string): boolean {
|
|
93
61
|
if (source === '') return true;
|
|
62
|
+
if (except && source.slice(0, except.length) === except) return false;
|
|
94
63
|
switch (source[0]) {
|
|
95
64
|
case ' ':
|
|
96
65
|
case ' ':
|