securemark 0.283.3 → 0.283.5
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/dist/index.js +142 -107
- package/markdown.d.ts +16 -8
- package/package.json +1 -1
- package/src/combinator/control/manipulation/surround.ts +4 -4
- package/src/combinator/data/parser/context/delimiter.ts +20 -20
- package/src/combinator/data/parser/context.ts +4 -3
- package/src/parser/block/blockquote.ts +1 -1
- package/src/parser/block/dlist.ts +6 -6
- package/src/parser/block/extension/aside.ts +1 -1
- package/src/parser/block/extension/example.ts +2 -2
- package/src/parser/block/extension/figure.ts +3 -3
- package/src/parser/block/extension/table.ts +5 -5
- package/src/parser/block/heading.ts +6 -6
- package/src/parser/block/ilist.ts +1 -1
- package/src/parser/block/olist.ts +1 -1
- package/src/parser/block/paragraph.ts +3 -3
- package/src/parser/block/reply.ts +2 -2
- package/src/parser/block/sidefence.ts +1 -1
- package/src/parser/block/table.ts +4 -4
- package/src/parser/block/ulist.ts +1 -1
- package/src/parser/block.ts +4 -3
- package/src/parser/context.ts +18 -9
- package/src/parser/inline/annotation.ts +7 -4
- package/src/parser/inline/autolink/account.ts +15 -14
- package/src/parser/inline/autolink/anchor.ts +14 -13
- package/src/parser/inline/autolink/channel.ts +6 -3
- package/src/parser/inline/autolink/email.ts +4 -3
- package/src/parser/inline/autolink/hashnum.ts +11 -9
- package/src/parser/inline/autolink/hashtag.ts +11 -9
- package/src/parser/inline/autolink/url.ts +24 -18
- package/src/parser/inline/autolink.ts +4 -5
- package/src/parser/inline/bracket.ts +6 -6
- package/src/parser/inline/code.ts +1 -1
- package/src/parser/inline/deletion.ts +1 -1
- package/src/parser/inline/emphasis.ts +1 -1
- package/src/parser/inline/emstrong.ts +1 -1
- package/src/parser/inline/extension/index.ts +9 -6
- package/src/parser/inline/extension/indexer.ts +1 -1
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/inline/extension/placeholder.ts +1 -1
- package/src/parser/inline/html.ts +45 -43
- package/src/parser/inline/htmlentity.ts +3 -3
- package/src/parser/inline/insertion.ts +1 -1
- package/src/parser/inline/link.test.ts +7 -2
- package/src/parser/inline/link.ts +11 -15
- package/src/parser/inline/mark.ts +1 -1
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/media.ts +4 -4
- package/src/parser/inline/reference.ts +7 -4
- package/src/parser/inline/remark.ts +4 -4
- package/src/parser/inline/ruby.ts +7 -6
- package/src/parser/inline/shortmedia.ts +1 -1
- package/src/parser/inline/strong.ts +1 -1
- package/src/parser/inline/template.ts +2 -2
- package/src/parser/inline.test.ts +1 -0
- package/src/parser/segment.ts +3 -2
- package/src/parser/source/escapable.ts +2 -2
- package/src/parser/source/str.ts +1 -1
- package/src/parser/source/text.ts +3 -3
- package/src/parser/source/unescapable.ts +4 -2
- package/src/parser/visibility.ts +14 -13
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import { union, constraint, validate, focus, convert, fmap, lazy } from '../../../combinator';
|
|
3
|
-
import { unsafelink } from '../link';
|
|
4
2
|
import { State } from '../../context';
|
|
3
|
+
import { union, syntax, constraint, validate, focus, convert, fmap, lazy } from '../../../combinator';
|
|
4
|
+
import { unsafelink } from '../link';
|
|
5
5
|
import { define } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
// Timeline(pseudonym): user/tid
|
|
@@ -14,16 +14,17 @@ import { define } from 'typed-dom/dom';
|
|
|
14
14
|
// 内部表現はUnixTimeに統一する(時系列順)
|
|
15
15
|
// 外部表現は投稿ごとに投稿者の投稿時のタイムゾーンに統一する(非時系列順)
|
|
16
16
|
|
|
17
|
-
export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>',
|
|
18
|
-
constraint(State.shortcut, false,
|
|
17
|
+
export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>',
|
|
19
18
|
focus(
|
|
20
19
|
/^>>(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*\/)?[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9a-z@#:])/i,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
union([
|
|
21
|
+
constraint(State.autolink, false, syntax(0, 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
|
+
([el]) => [define(el, { class: 'anchor' })]))),
|
|
29
|
+
({ source }) => [[source], ''],
|
|
30
|
+
]))));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State } from '../../context';
|
|
3
|
+
import { sequence, some, constraint, validate, bind } from '../../../combinator';
|
|
3
4
|
import { account } from './account';
|
|
4
5
|
import { hashtag } from './hashtag';
|
|
5
6
|
import { stringify } from '../../util';
|
|
@@ -7,7 +8,8 @@ import { define } from 'typed-dom/dom';
|
|
|
7
8
|
|
|
8
9
|
// https://example/@user?ch=a+b must be a user channel page or a redirect page going there.
|
|
9
10
|
|
|
10
|
-
export const channel: AutolinkParser.ChannelParser = validate('@',
|
|
11
|
+
export const channel: AutolinkParser.ChannelParser = validate('@',
|
|
12
|
+
constraint(State.autolink, false, bind(
|
|
11
13
|
sequence([
|
|
12
14
|
account,
|
|
13
15
|
some(hashtag),
|
|
@@ -15,6 +17,7 @@ export const channel: AutolinkParser.ChannelParser = validate('@', bind(
|
|
|
15
17
|
(es, rest) => {
|
|
16
18
|
const source = stringify(es);
|
|
17
19
|
const el = es[0];
|
|
20
|
+
if (typeof el === 'string') return [es, rest];
|
|
18
21
|
const url = `${el.getAttribute('href')}?ch=${source.slice(source.indexOf('#') + 1).replace(/#/g, '+')}`;
|
|
19
22
|
return [[define(el, { class: 'channel', href: url }, source)], rest];
|
|
20
|
-
}));
|
|
23
|
+
})));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State, Recursion } from '../../context';
|
|
3
|
+
import { syntax, creation, constraint, verify, rewrite } from '../../../combinator';
|
|
3
4
|
import { str } from '../../source';
|
|
4
|
-
import { Recursion } from '../../context';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
// https://html.spec.whatwg.org/multipage/input.html
|
|
@@ -9,4 +9,5 @@ import { html } from 'typed-dom/dom';
|
|
|
9
9
|
export const email: AutolinkParser.EmailParser = creation(1, Recursion.ignore, rewrite(verify(
|
|
10
10
|
str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[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])?)*(?![0-9a-z])/i),
|
|
11
11
|
([source]) => source.length <= 255),
|
|
12
|
-
(
|
|
12
|
+
constraint(State.autolink, false, syntax(0, State.autolink,
|
|
13
|
+
({ source }) => [[html('a', { class: 'email', href: `mailto:${source}` }, source)], '']))));
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State } from '../../context';
|
|
3
|
+
import { union, syntax, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
|
|
3
4
|
import { unsafelink } from '../link';
|
|
4
5
|
import { emoji } from './hashtag';
|
|
5
6
|
import { str } from '../../source';
|
|
6
|
-
import { State } from '../../context';
|
|
7
7
|
import { define } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
|
-
export const hashnum: AutolinkParser.HashnumParser = lazy(() =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
export const hashnum: AutolinkParser.HashnumParser = lazy(() => rewrite(
|
|
10
|
+
open('#', str(new RegExp(/^[0-9]{1,9}(?![^\p{C}\p{S}\p{P}\s]|emoji|['_])/u.source.replace(/emoji/, emoji), 'u'))),
|
|
11
|
+
union([
|
|
12
|
+
constraint(State.autolink, false, syntax(0, State.autolink, fmap(convert(
|
|
13
|
+
source => `[${source}]{ ${source.slice(1)} }`,
|
|
14
|
+
unsafelink),
|
|
15
|
+
([el]) => [define(el, { class: 'hashnum', href: null })]))),
|
|
16
|
+
({ source }) => [[source], ''],
|
|
17
|
+
])));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State } from '../../context';
|
|
3
|
+
import { union, syntax, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
|
|
3
4
|
import { unsafelink } from '../link';
|
|
4
5
|
import { str } from '../../source';
|
|
5
|
-
import { State } from '../../context';
|
|
6
6
|
import { define } from 'typed-dom/dom';
|
|
7
7
|
|
|
8
8
|
// https://example/hashtags/a must be a hashtag page or a redirect page going there.
|
|
@@ -10,15 +10,17 @@ import { define } from 'typed-dom/dom';
|
|
|
10
10
|
// https://github.com/tc39/proposal-regexp-unicode-property-escapes#matching-emoji
|
|
11
11
|
export const emoji = String.raw`\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F`;
|
|
12
12
|
|
|
13
|
-
export const hashtag: AutolinkParser.HashtagParser = lazy(() =>
|
|
14
|
-
constraint(State.shortcut, false,
|
|
13
|
+
export const hashtag: AutolinkParser.HashtagParser = lazy(() => rewrite(
|
|
15
14
|
open(
|
|
16
15
|
'#',
|
|
17
16
|
str(new RegExp([
|
|
18
17
|
/^(?!['_])(?=(?:[0-9]{1,9})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'|_(?=[^\p{C}\p{S}\p{P}\s]|emoji|')))/u.source,
|
|
19
18
|
/(?:[^\p{C}\p{S}\p{P}\s]|emoji|'|_(?=[^\p{C}\p{S}\p{P}\s]|emoji|'))+/u.source,
|
|
20
|
-
].join('').replace(/emoji/g, emoji), 'u')))
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
].join('').replace(/emoji/g, emoji), 'u'))),
|
|
20
|
+
union([
|
|
21
|
+
constraint(State.autolink, false, syntax(0, State.autolink, fmap(convert(
|
|
22
|
+
source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`,
|
|
23
|
+
unsafelink),
|
|
24
|
+
([el]) => [define(el, { class: 'hashtag' })]))),
|
|
25
|
+
({ source }) => [[source], ''],
|
|
26
|
+
])));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State, Recursion, Backtrack } from '../../context';
|
|
3
|
+
import { union, tails, some, syntax, creation, precedence, constraint, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
|
|
3
4
|
import { unsafelink } from '../link';
|
|
4
5
|
import { linebreak, unescsource, str } from '../../source';
|
|
5
|
-
import { Backtrack, Recursion } from '../../context';
|
|
6
6
|
|
|
7
7
|
const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
|
|
8
8
|
|
|
@@ -10,24 +10,30 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
|
|
|
10
10
|
open(
|
|
11
11
|
/^https?:\/\/(?=[\x21-\x7E])/,
|
|
12
12
|
focus(/^[\x21-\x7E]+/, some(union([bracket, some(unescsource, closer)])))),
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
union([
|
|
14
|
+
constraint(State.autolink, false, syntax(0, State.autolink, convert(
|
|
15
|
+
url => `{ ${url} }`,
|
|
16
|
+
unsafelink))),
|
|
17
|
+
({ source }) => [[source], ''],
|
|
18
|
+
]))));
|
|
16
19
|
|
|
17
20
|
export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
|
|
18
21
|
linebreak,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
focus(
|
|
23
|
+
/^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
24
|
+
tails([
|
|
25
|
+
str('!'),
|
|
26
|
+
union([
|
|
27
|
+
constraint(State.autolink, false, syntax(0, State.autolink, convert(
|
|
28
|
+
url => `{ ${url} }`,
|
|
29
|
+
unsafelink))),
|
|
30
|
+
({ source }) => [[source], ''],
|
|
31
|
+
]),
|
|
32
|
+
]))));
|
|
27
33
|
|
|
28
|
-
const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal,
|
|
29
|
-
surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.url),
|
|
30
|
-
surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.url),
|
|
31
|
-
surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.url),
|
|
34
|
+
const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
|
|
35
|
+
surround(str('('), precedence(1, some(union([bracket, unescsource]), ')')), str(')'), true, undefined, undefined, 3 | Backtrack.url),
|
|
36
|
+
surround(str('['), precedence(1, some(union([bracket, unescsource]), ']')), str(']'), true, undefined, undefined, 3 | Backtrack.url),
|
|
37
|
+
surround(str('{'), precedence(1, some(union([bracket, unescsource]), '}')), str('}'), true, undefined, undefined, 3 | Backtrack.url),
|
|
32
38
|
surround(str('"'), precedence(2, some(unescsource, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.url),
|
|
33
|
-
])))
|
|
39
|
+
])));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AutolinkParser } from '../inline';
|
|
2
|
-
import {
|
|
2
|
+
import { State } from '../context';
|
|
3
|
+
import { union, some, syntax, validate, lazy, fmap } from '../../combinator';
|
|
3
4
|
import { url, lineurl } from './autolink/url';
|
|
4
5
|
import { email } from './autolink/email';
|
|
5
6
|
import { channel } from './autolink/channel';
|
|
@@ -8,13 +9,11 @@ import { hashtag, emoji } from './autolink/hashtag';
|
|
|
8
9
|
import { hashnum } from './autolink/hashnum';
|
|
9
10
|
import { anchor } from './autolink/anchor';
|
|
10
11
|
import { str } from '../source';
|
|
11
|
-
import { State } from '../context';
|
|
12
12
|
import { stringify } from '../util';
|
|
13
13
|
|
|
14
14
|
export const autolink: AutolinkParser = lazy(() =>
|
|
15
15
|
validate(/^(?:[@#>0-9a-z]|\S[#>]|[\r\n]!?https?:\/\/)/iu,
|
|
16
|
-
|
|
17
|
-
syntax(0, ~State.shortcut,
|
|
16
|
+
syntax(0, ~State.autolink,
|
|
18
17
|
union([
|
|
19
18
|
some(union([lineurl])),
|
|
20
19
|
fmap(some(union([
|
|
@@ -37,4 +36,4 @@ export const autolink: AutolinkParser = lazy(() =>
|
|
|
37
36
|
anchor,
|
|
38
37
|
])),
|
|
39
38
|
ns => ns.length === 1 ? ns : [stringify(ns)]),
|
|
40
|
-
]))))
|
|
39
|
+
]))));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BracketParser } from '../inline';
|
|
2
|
+
import { State, Recursion, Backtrack } from '../context';
|
|
2
3
|
import { union, some, syntax, creation, surround, lazy } from '../../combinator';
|
|
3
4
|
import { inline } from '../inline';
|
|
4
5
|
import { str } from '../source';
|
|
5
|
-
import { State, Recursion, Backtrack } from '../context';
|
|
6
6
|
import { unshift, push } from 'spica/array';
|
|
7
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
8
|
|
|
@@ -32,19 +32,19 @@ export const bracket: BracketParser = lazy(() => union([
|
|
|
32
32
|
undefined,
|
|
33
33
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
34
34
|
// 改行禁止はバックトラックなしでは内側の構文を破壊するため安易に行えない。
|
|
35
|
-
surround(str('"'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '"', [[
|
|
35
|
+
surround(str('"'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '"', [['\n', 9], ['"', 2]]))), str('"'), true,
|
|
36
36
|
undefined,
|
|
37
37
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
38
|
-
surround(str('“'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '”', [[
|
|
38
|
+
surround(str('“'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '”', [['\n', 9], ['”', 2]]))), str('”'), true,
|
|
39
39
|
undefined,
|
|
40
40
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
41
|
-
surround(str('‘'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '’', [[
|
|
41
|
+
surround(str('‘'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '’', [['\n', 9], ['’', 2]]))), str('’'), true,
|
|
42
42
|
undefined,
|
|
43
43
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
44
|
-
surround(str('「'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '」', [[
|
|
44
|
+
surround(str('「'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '」', [['\n', 9], ['」', 2]]))), str('」'), true,
|
|
45
45
|
undefined,
|
|
46
46
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
47
|
-
surround(str('『'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '』', [[
|
|
47
|
+
surround(str('『'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '』', [['\n', 9], ['』', 2]]))), str('』'), true,
|
|
48
48
|
undefined,
|
|
49
49
|
([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
50
50
|
]));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CodeParser } from '../inline';
|
|
2
|
-
import { creation, validate, match } from '../../combinator';
|
|
3
2
|
import { Recursion } from '../context';
|
|
3
|
+
import { creation, validate, match } from '../../combinator';
|
|
4
4
|
import { html } from 'typed-dom/dom';
|
|
5
5
|
|
|
6
6
|
export const code: CodeParser = creation(1, Recursion.ignore, validate('`', match(
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DeletionParser } from '../inline';
|
|
2
|
+
import { State, Recursion } from '../context';
|
|
2
3
|
import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
|
|
3
4
|
import { inline } from '../inline';
|
|
4
5
|
import { str } from '../source';
|
|
5
|
-
import { State, Recursion } from '../context';
|
|
6
6
|
import { blankWith } from '../visibility';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { EmphasisParser } from '../inline';
|
|
2
|
+
import { State, Recursion } from '../context';
|
|
2
3
|
import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
|
|
3
4
|
import { inline } from '../inline';
|
|
4
5
|
import { emstrong } from './emstrong';
|
|
5
6
|
import { strong } from './strong';
|
|
6
7
|
import { str } from '../source';
|
|
7
|
-
import { State, Recursion } from '../context';
|
|
8
8
|
import { startTight, blankWith } from '../visibility';
|
|
9
9
|
import { unshift } from 'spica/array';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
|
|
2
|
+
import { State, Recursion } from '../context';
|
|
2
3
|
import { Result, IntermediateParser } from '../../combinator/data/parser';
|
|
3
4
|
import { union, syntax, creation, some, surround, open, lazy, bind } from '../../combinator';
|
|
4
5
|
import { inline } from '../inline';
|
|
5
6
|
import { strong } from './strong';
|
|
6
7
|
import { emphasis } from './emphasis';
|
|
7
8
|
import { str } from '../source';
|
|
8
|
-
import { State, Recursion } from '../context';
|
|
9
9
|
import { startTight, blankWith } from '../visibility';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
import { unshift } from 'spica/array';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
+
import { State, Recursion, Backtrack } from '../../context';
|
|
2
3
|
import { union, inits, some, syntax, creation, precedence, constraint, validate, surround, open, lazy, fmap } from '../../../combinator';
|
|
3
4
|
import { inline } from '../../inline';
|
|
4
5
|
import { indexee, identity } from './indexee';
|
|
5
6
|
import { txt, str } from '../../source';
|
|
6
|
-
import {
|
|
7
|
-
import { startTight, trimNodeEnd } from '../../visibility';
|
|
7
|
+
import { startTight, trimBlankNodeEnd } from '../../visibility';
|
|
8
8
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
import IndexParser = ExtensionParser.IndexParser;
|
|
@@ -17,10 +17,13 @@ export const index: IndexParser = lazy(() => validate('[#', creation(1, Recursio
|
|
|
17
17
|
some(inits([
|
|
18
18
|
inline,
|
|
19
19
|
signature,
|
|
20
|
-
]), ']', [[
|
|
20
|
+
]), ']', [['\n', 9], [']', 1]])))),
|
|
21
21
|
']',
|
|
22
22
|
false,
|
|
23
|
-
([, ns], rest) =>
|
|
23
|
+
([, ns], rest) =>
|
|
24
|
+
trimBlankNodeEnd(ns).length > 0
|
|
25
|
+
? [[html('a', { 'data-index': dataindex(ns) }, defrag(ns))], rest]
|
|
26
|
+
: undefined,
|
|
24
27
|
undefined, 1 | Backtrack.bracket)),
|
|
25
28
|
([el]: [HTMLAnchorElement]) => [
|
|
26
29
|
define(el,
|
|
@@ -32,8 +35,8 @@ export const index: IndexParser = lazy(() => validate('[#', creation(1, Recursio
|
|
|
32
35
|
]))));
|
|
33
36
|
|
|
34
37
|
export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(1, Recursion.ignore, fmap(open(
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
/^\|(?!\\?\s)/,
|
|
39
|
+
some(union([bracket, txt]), ']')),
|
|
37
40
|
ns => [
|
|
38
41
|
html('span', { class: 'indexer', 'data-index': identity('index', undefined, ns.join(''))!.slice(7) }),
|
|
39
42
|
]))));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
+
import { Recursion } from '../../context';
|
|
2
3
|
import { union, creation, focus, surround } from '../../../combinator';
|
|
3
4
|
import { signature } from './index';
|
|
4
|
-
import { Recursion } from '../../context';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
export const indexer: ExtensionParser.IndexerParser = surround(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
+
import { State, Recursion } from '../../context';
|
|
2
3
|
import { union, constraint, creation, validate, surround, clear, fmap } from '../../../combinator';
|
|
3
4
|
import { str } from '../../source';
|
|
4
|
-
import { State, Recursion } from '../../context';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
const body = str(/^\$[A-Za-z]*(?:(?:-[A-Za-z][0-9A-Za-z]*)+|-(?:(?:0|[1-9][0-9]*)\.)*(?:0|[1-9][0-9]*)(?![0-9A-Za-z]))/);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
|
+
import { State, Recursion, Backtrack } from '../../context';
|
|
2
3
|
import { union, some, syntax, creation, validate, surround, lazy } from '../../../combinator';
|
|
3
4
|
import { inline } from '../../inline';
|
|
4
5
|
import { str } from '../../source';
|
|
5
|
-
import { State, Recursion, Backtrack } from '../../context';
|
|
6
6
|
import { startTight } from '../../visibility';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { HTMLParser } from '../inline';
|
|
2
|
+
import { State, Recursion } from '../context';
|
|
2
3
|
import { union, subsequence, some, syntax, creation, validate, focus, surround, open, match, lazy } from '../../combinator';
|
|
3
4
|
import { inline } from '../inline';
|
|
4
5
|
import { str } from '../source';
|
|
5
|
-
import { State, Recursion } from '../context';
|
|
6
6
|
import { isStartLooseNodes, blankWith } from '../visibility';
|
|
7
7
|
import { memoize } from 'spica/memoize';
|
|
8
8
|
import { Clock } from 'spica/clock';
|
|
@@ -18,48 +18,50 @@ const attrspecs = {
|
|
|
18
18
|
Object.setPrototypeOf(attrspecs, null);
|
|
19
19
|
Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
|
|
20
20
|
|
|
21
|
-
export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, creation(1, Recursion.inline,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
])
|
|
21
|
+
export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, creation(1, Recursion.inline,
|
|
22
|
+
syntax(3, State.none,
|
|
23
|
+
union([
|
|
24
|
+
focus(
|
|
25
|
+
/^<wbr[^\S\n]*>/i,
|
|
26
|
+
() => [[h('wbr')], '']),
|
|
27
|
+
surround(
|
|
28
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
29
|
+
str(/^<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[^\S\n]|>)/i), some(union([attribute])), str(/^[^\S\n]*>/), true,
|
|
30
|
+
([as, bs = [], cs], rest) =>
|
|
31
|
+
[[elem(as[0].slice(1), push(unshift(as, bs), cs), [], [])], rest]),
|
|
32
|
+
match(
|
|
33
|
+
new RegExp(String.raw`^<(${TAGS.join('|')})(?=[^\S\n]|>)`),
|
|
34
|
+
memoize(
|
|
35
|
+
([, tag]) =>
|
|
36
|
+
surround<HTMLParser.TagParser, string>(surround(
|
|
37
|
+
str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
|
|
38
|
+
subsequence([
|
|
39
|
+
focus(/^[^\S\n]*\n/, some(inline)),
|
|
40
|
+
some(open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`), 3]]), true)),
|
|
41
|
+
]),
|
|
42
|
+
str(`</${tag}>`), true,
|
|
43
|
+
([as, bs = [], cs], rest) =>
|
|
44
|
+
[[elem(tag, as, bs, cs)], rest],
|
|
45
|
+
([as, bs = []], rest) =>
|
|
46
|
+
[[elem(tag, as, bs, [])], rest]))),
|
|
47
|
+
match(
|
|
48
|
+
/^<([a-z]+)(?=[^\S\n]|>)/i,
|
|
49
|
+
memoize(
|
|
50
|
+
([, tag]) =>
|
|
51
|
+
surround<HTMLParser.TagParser, string>(surround(
|
|
52
|
+
str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
|
|
53
|
+
subsequence([
|
|
54
|
+
focus(/^[^\S\n]*\n/, some(inline)),
|
|
55
|
+
some(inline, `</${tag}>`, [[`</${tag}>`, 3]]),
|
|
56
|
+
]),
|
|
57
|
+
str(`</${tag}>`), true,
|
|
58
|
+
([as, bs = [], cs], rest) =>
|
|
59
|
+
[[elem(tag, as, bs, cs)], rest],
|
|
60
|
+
([as, bs = []], rest) =>
|
|
61
|
+
[[elem(tag, as, bs, [])], rest]),
|
|
62
|
+
([, tag]) => tag,
|
|
63
|
+
new Clock(10000))),
|
|
64
|
+
]))))));
|
|
63
65
|
|
|
64
66
|
export const attribute: HTMLParser.AttributeParser = union([
|
|
65
67
|
str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="[^"\n]*")?(?=[^\S\n]|>)/i),
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { HTMLEntityParser, UnsafeHTMLEntityParser } from '../inline';
|
|
2
|
+
import { Recursion, Command } from '../context';
|
|
2
3
|
import { union, creation, validate, focus, fmap } from '../../combinator';
|
|
3
|
-
import { Recursion } from '../context';
|
|
4
4
|
import { html } from 'typed-dom/dom';
|
|
5
5
|
import { reduce } from 'spica/memoize';
|
|
6
6
|
|
|
7
7
|
export const unsafehtmlentity: UnsafeHTMLEntityParser = creation(1, Recursion.ignore, validate('&', focus(
|
|
8
8
|
/^&[0-9A-Za-z]{1,99};/,
|
|
9
|
-
({ source }) => [[parse(source) ??
|
|
9
|
+
({ source }) => [[parse(source) ?? `${Command.Escape}${source}`], ''])));
|
|
10
10
|
|
|
11
11
|
export const htmlentity: HTMLEntityParser = fmap(
|
|
12
12
|
union([unsafehtmlentity]),
|
|
13
13
|
([text]) => [
|
|
14
|
-
text[0] ===
|
|
14
|
+
text[0] === Command.Escape
|
|
15
15
|
? html('span', {
|
|
16
16
|
class: 'invalid',
|
|
17
17
|
'data-invalid-syntax': 'htmlentity',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InsertionParser } from '../inline';
|
|
2
|
+
import { State, Recursion } from '../context';
|
|
2
3
|
import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
|
|
3
4
|
import { inline } from '../inline';
|
|
4
5
|
import { str } from '../source';
|
|
5
|
-
import { State, Recursion } from '../context';
|
|
6
6
|
import { blankWith } from '../visibility';
|
|
7
7
|
import { unshift } from 'spica/array';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { LinkParser } from '../inline';
|
|
2
|
+
import { textlink, medialink } from './link';
|
|
3
|
+
import { some, union } from '../../combinator';
|
|
3
4
|
import { inspect } from '../../debug.test';
|
|
4
5
|
import { MarkdownParser } from '../../../markdown';
|
|
5
6
|
|
|
6
7
|
describe('Unit: parser/inline/link', () => {
|
|
7
8
|
describe('link', () => {
|
|
9
|
+
const link: LinkParser = union([
|
|
10
|
+
medialink,
|
|
11
|
+
textlink,
|
|
12
|
+
]);
|
|
8
13
|
const parser = (source: string, context: MarkdownParser.Context = {}) => some(link)({ source, context });
|
|
9
14
|
|
|
10
15
|
it('xss', () => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../../markdown';
|
|
2
2
|
import { LinkParser } from '../inline';
|
|
3
|
+
import { State, Recursion, Backtrack } from '../context';
|
|
3
4
|
import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
4
5
|
import { inline, media, shortmedia } from '../inline';
|
|
5
6
|
import { attributes } from './html';
|
|
6
7
|
import { linebreak, unescsource, str } from '../source';
|
|
7
|
-
import {
|
|
8
|
-
import { trimBlankStart, trimNodeEnd } from '../visibility';
|
|
8
|
+
import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
|
|
9
9
|
import { stringify } from '../util';
|
|
10
10
|
import { ReadonlyURL } from 'spica/url';
|
|
11
11
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
@@ -15,18 +15,13 @@ const optspec = {
|
|
|
15
15
|
} as const;
|
|
16
16
|
Object.setPrototypeOf(optspec, null);
|
|
17
17
|
|
|
18
|
-
export const
|
|
19
|
-
medialink,
|
|
20
|
-
textlink,
|
|
21
|
-
])));
|
|
22
|
-
|
|
23
|
-
export const textlink: LinkParser.TextLinkParser = lazy(() => creation(1, Recursion.ignore,
|
|
18
|
+
export const textlink: LinkParser.TextLinkParser = lazy(() => validate(['[', '{'], creation(1, Recursion.ignore,
|
|
24
19
|
constraint(State.link, false,
|
|
25
20
|
syntax(1, State.linkers | State.media,
|
|
26
21
|
bind(reverse(tails([
|
|
27
22
|
dup(surround(
|
|
28
23
|
'[',
|
|
29
|
-
trimBlankStart(some(union([inline]), ']', [[
|
|
24
|
+
trimBlankStart(some(union([inline]), ']', [['\n', 9], [']', 1]])),
|
|
30
25
|
']',
|
|
31
26
|
true, undefined, undefined, 1 | Backtrack.bracket)),
|
|
32
27
|
dup(surround(
|
|
@@ -38,11 +33,11 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => creation(1, Recurs
|
|
|
38
33
|
([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
|
|
39
34
|
assert(!html('div', content).querySelector('a, .media, .annotation, .reference'));
|
|
40
35
|
assert(content[0] !== '');
|
|
41
|
-
if (content.length !== 0 &&
|
|
42
|
-
return [[parse(content, params, context)], rest];
|
|
43
|
-
})))));
|
|
36
|
+
if (content.length !== 0 && trimBlankNodeEnd(content).length === 0) return;
|
|
37
|
+
return [[parse(defrag(content), params, context)], rest];
|
|
38
|
+
}))))));
|
|
44
39
|
|
|
45
|
-
export const medialink: LinkParser.MediaLinkParser = lazy(() => creation(1, Recursion.ignore,
|
|
40
|
+
export const medialink: LinkParser.MediaLinkParser = lazy(() => validate(['[', '{'], creation(1, Recursion.ignore,
|
|
46
41
|
constraint(State.link | State.media, false,
|
|
47
42
|
syntax(1, State.linkers,
|
|
48
43
|
bind(reverse(sequence([
|
|
@@ -53,7 +48,7 @@ export const medialink: LinkParser.MediaLinkParser = lazy(() => creation(1, Recu
|
|
|
53
48
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
|
|
54
49
|
])),
|
|
55
50
|
([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) =>
|
|
56
|
-
[[parse(defrag(content), params, context)], rest])))));
|
|
51
|
+
[[parse(defrag(content), params, context)], rest]))))));
|
|
57
52
|
|
|
58
53
|
export const linemedialink: LinkParser.LineMediaLinkParser = surround(
|
|
59
54
|
linebreak,
|
|
@@ -61,7 +56,8 @@ export const linemedialink: LinkParser.LineMediaLinkParser = surround(
|
|
|
61
56
|
/^(?=[^\S\n]*(?:$|\n))/);
|
|
62
57
|
|
|
63
58
|
export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
|
|
64
|
-
creation(1, Recursion.ignore,
|
|
59
|
+
creation(1, Recursion.ignore,
|
|
60
|
+
precedence(1,
|
|
65
61
|
bind(reverse(tails([
|
|
66
62
|
dup(surround(
|
|
67
63
|
'[',
|