securemark 0.257.2 → 0.258.1
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/index.js +1238 -618
- package/markdown.d.ts +1 -12
- package/package.json +9 -9
- package/src/combinator/control/manipulation/convert.ts +8 -4
- package/src/combinator/control/manipulation/scope.ts +10 -2
- package/src/combinator/data/parser/context/delimiter.ts +70 -0
- package/src/combinator/data/parser/context/memo.ts +34 -0
- package/src/combinator/{control/manipulation → data/parser}/context.test.ts +9 -9
- package/src/combinator/data/parser/context.ts +158 -0
- package/src/combinator/data/parser/inits.ts +4 -3
- package/src/combinator/data/parser/sequence.test.ts +1 -1
- package/src/combinator/data/parser/sequence.ts +4 -3
- package/src/combinator/data/parser/some.test.ts +1 -1
- package/src/combinator/data/parser/some.ts +14 -37
- package/src/combinator/data/parser/subsequence.test.ts +1 -1
- package/src/combinator/data/parser/subsequence.ts +3 -3
- package/src/combinator/data/parser/tails.ts +3 -3
- package/src/combinator/data/parser/union.test.ts +1 -1
- package/src/combinator/data/parser.ts +6 -47
- package/src/combinator.ts +1 -2
- package/src/parser/api/bind.ts +5 -5
- package/src/parser/api/parse.test.ts +11 -8
- package/src/parser/api/parse.ts +3 -1
- package/src/parser/block/blockquote.ts +1 -1
- package/src/parser/block/dlist.ts +4 -10
- package/src/parser/block/extension/figure.ts +4 -3
- package/src/parser/block/extension/table.ts +2 -2
- package/src/parser/block/heading.ts +5 -13
- package/src/parser/block/ilist.ts +3 -2
- package/src/parser/block/olist.ts +10 -7
- package/src/parser/block/paragraph.ts +1 -1
- package/src/parser/block/reply/cite.ts +1 -1
- package/src/parser/block/reply/quote.ts +1 -1
- package/src/parser/block/reply.ts +1 -1
- package/src/parser/block/sidefence.ts +1 -1
- package/src/parser/block/table.test.ts +5 -0
- package/src/parser/block/table.ts +14 -13
- package/src/parser/block/ulist.ts +4 -3
- package/src/parser/block.ts +1 -1
- package/src/parser/context.ts +32 -0
- package/src/parser/header.ts +1 -1
- package/src/parser/inline/annotation.test.ts +5 -5
- package/src/parser/inline/annotation.ts +9 -17
- package/src/parser/inline/autolink/email.ts +1 -1
- package/src/parser/inline/autolink/url.ts +1 -1
- package/src/parser/inline/autolink.ts +5 -3
- package/src/parser/inline/bracket.ts +16 -15
- package/src/parser/inline/code.ts +1 -1
- package/src/parser/inline/comment.ts +4 -3
- package/src/parser/inline/deletion.ts +5 -4
- package/src/parser/inline/emphasis.ts +5 -4
- package/src/parser/inline/emstrong.ts +5 -4
- package/src/parser/inline/extension/index.ts +7 -14
- package/src/parser/inline/extension/indexee.ts +8 -10
- package/src/parser/inline/extension/indexer.ts +4 -3
- package/src/parser/inline/extension/label.ts +3 -2
- package/src/parser/inline/extension/placeholder.ts +5 -4
- package/src/parser/inline/html.ts +5 -4
- package/src/parser/inline/htmlentity.ts +1 -1
- package/src/parser/inline/insertion.ts +5 -4
- package/src/parser/inline/link.test.ts +2 -1
- package/src/parser/inline/link.ts +21 -27
- package/src/parser/inline/mark.ts +5 -4
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/media.test.ts +1 -0
- package/src/parser/inline/media.ts +8 -7
- package/src/parser/inline/reference.test.ts +5 -5
- package/src/parser/inline/reference.ts +10 -16
- package/src/parser/inline/ruby.test.ts +1 -0
- package/src/parser/inline/ruby.ts +4 -3
- package/src/parser/inline/shortmedia.ts +3 -2
- package/src/parser/inline/strong.ts +5 -4
- package/src/parser/inline/template.test.ts +1 -1
- package/src/parser/inline/template.ts +9 -6
- package/src/parser/inline.test.ts +2 -1
- package/src/parser/locale.ts +6 -7
- package/src/parser/processor/footnote.ts +5 -3
- package/src/parser/source/text.ts +1 -1
- package/src/parser/util.ts +0 -220
- package/src/parser/visibility.ts +205 -0
- package/src/util/info.ts +4 -2
- package/src/util/quote.ts +12 -15
- package/src/util/toc.ts +14 -17
- package/webpack.config.js +1 -0
- package/src/combinator/control/manipulation/context.ts +0 -70
- package/src/combinator/control/manipulation/resource.ts +0 -54
|
@@ -18,11 +18,11 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('[[\\\na]]')), undefined);
|
|
21
|
-
assert.deepStrictEqual(inspect(parser('[[a\n]]')),
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('[[a\\\n]]')),
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('[[a\nb]]')),
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('[[a\\\nb]]')),
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')),
|
|
21
|
+
assert.deepStrictEqual(inspect(parser('[[a\n]]')), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser('[[a\\\n]]')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('[[a\nb]]')), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('[[a\\\nb]]')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), undefined);
|
|
26
26
|
assert.deepStrictEqual(inspect(parser('[[\\]]')), undefined);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser('[[a]b]]')), undefined);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('[[[a]]')), undefined);
|
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { ReferenceParser } from '../inline';
|
|
3
|
-
import { union, subsequence, some,
|
|
3
|
+
import { union, subsequence, some, context, creator, guard, syntax, state, validate, surround, open, lazy, bind } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { optimize } from './link';
|
|
6
6
|
import { str, stropt } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { Rule, State } from '../context';
|
|
8
|
+
import { regBlankStart, startLoose, trimNode } from '../visibility';
|
|
9
|
+
import { stringify } from '../util';
|
|
8
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
11
|
|
|
10
|
-
export const reference: ReferenceParser = lazy(() => validate('[[',
|
|
12
|
+
export const reference: ReferenceParser = lazy(() => validate('[[', syntax(Rule.reference, 6, surround(
|
|
11
13
|
'[[',
|
|
12
|
-
guard(context => context.
|
|
14
|
+
guard(context => ~context.state! & State.reference,
|
|
15
|
+
state(State.annotation | State.reference | State.media,
|
|
13
16
|
startLoose(
|
|
14
|
-
context({
|
|
15
|
-
annotation: false,
|
|
16
|
-
reference: false,
|
|
17
|
-
media: false,
|
|
18
|
-
// Redundant
|
|
19
|
-
//index: true,
|
|
20
|
-
//label: true,
|
|
21
|
-
//link: true,
|
|
22
|
-
//autolink: true,
|
|
23
|
-
}}, delimiters: undefined },
|
|
17
|
+
context({ delimiters: undefined },
|
|
24
18
|
subsequence([
|
|
25
19
|
abbr,
|
|
26
20
|
open(stropt(/^(?=\^)/), some(inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])),
|
|
27
21
|
some(inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]]),
|
|
28
|
-
])), ']')),
|
|
22
|
+
])), ']'))),
|
|
29
23
|
']]',
|
|
30
24
|
false,
|
|
31
25
|
([, ns], rest) => [[html('sup', attributes(ns), [html('span', trimNode(defrag(ns)))])], rest],
|
|
32
|
-
([, ns, rest], next) => next[0] === ']' ? undefined : optimize('[[', ns, rest)))))
|
|
26
|
+
([, ns, rest], next) => next[0] === ']' ? undefined : optimize('[[', ns, rest, next)))));
|
|
33
27
|
|
|
34
28
|
const abbr: ReferenceParser.AbbrParser = creator(bind(surround(
|
|
35
29
|
'^',
|
|
@@ -8,6 +8,7 @@ describe('Unit: parser/inline/ruby', () => {
|
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
11
|
+
assert.deepStrictEqual(inspect(parser('[(b)')), undefined);
|
|
11
12
|
assert.deepStrictEqual(inspect(parser('[]()')), undefined);
|
|
12
13
|
assert.deepStrictEqual(inspect(parser('[](b)')), undefined);
|
|
13
14
|
assert.deepStrictEqual(inspect(parser('[ ](b)')), undefined);
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { RubyParser } from '../inline';
|
|
3
3
|
import { eval, exec } from '../../combinator/data/parser';
|
|
4
|
-
import { sequence, validate, verify, focus,
|
|
4
|
+
import { sequence, syntax, creator, validate, verify, focus, surround, lazy, fmap } from '../../combinator';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
6
|
import { text as txt } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { Rule } from '../context';
|
|
8
|
+
import { isStartTightNodes } from '../visibility';
|
|
8
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
10
|
import { unshift, push } from 'spica/array';
|
|
10
11
|
|
|
11
|
-
export const ruby: RubyParser = lazy(() => validate('[',
|
|
12
|
+
export const ruby: RubyParser = lazy(() => validate('[', syntax(Rule.none, 2, fmap(verify(
|
|
12
13
|
sequence([
|
|
13
14
|
surround('[', focus(/^(?:\\[^\n]|[^\\[\](){}"\n])+(?=]\()/, text), ']'),
|
|
14
15
|
surround('(', focus(/^(?:\\[^\n]|[^\\[\](){}"\n])+(?=\))/, text), ')'),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ShortmediaParser } from '../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, guard, rewrite, open, convert } from '../../combinator';
|
|
3
3
|
import { url } from './autolink/url';
|
|
4
4
|
import { media } from './media';
|
|
5
|
+
import { State } from '../context';
|
|
5
6
|
|
|
6
7
|
export const shortmedia: ShortmediaParser = rewrite(
|
|
7
|
-
guard(context => context.
|
|
8
|
+
guard(context => ~context.state! & State.media,
|
|
8
9
|
open('!', url)),
|
|
9
10
|
convert(
|
|
10
11
|
source => `!{ ${source.slice(1)} }`,
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { StrongParser } from '../inline';
|
|
2
|
-
import { union, some,
|
|
2
|
+
import { union, some, syntax, surround, open, lazy } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { emstrong } from './emstrong';
|
|
5
5
|
import { str } from '../source';
|
|
6
|
-
import {
|
|
6
|
+
import { Rule } from '../context';
|
|
7
|
+
import { startTight, blankWith } from '../visibility';
|
|
7
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
9
|
import { unshift } from 'spica/array';
|
|
9
10
|
|
|
10
|
-
export const strong: StrongParser = lazy(() =>
|
|
11
|
+
export const strong: StrongParser = lazy(() => syntax(Rule.none, 1, surround(
|
|
11
12
|
str('**'),
|
|
12
13
|
startTight(some(union([
|
|
13
14
|
some(inline, blankWith('**')),
|
|
@@ -18,4 +19,4 @@ export const strong: StrongParser = lazy(() => creator(precedence(1, surround(
|
|
|
18
19
|
])), '*'),
|
|
19
20
|
str('**'), false,
|
|
20
21
|
([, bs], rest) => [[html('strong', defrag(bs))], rest],
|
|
21
|
-
([as, bs], rest) => [unshift(as, bs), rest])))
|
|
22
|
+
([as, bs], rest) => [unshift(as, bs), rest])));
|
|
@@ -10,7 +10,7 @@ describe('Unit: parser/inline/template', () => {
|
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('{')), undefined);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('{}')), undefined);
|
|
13
|
-
assert.deepStrictEqual(inspect(parser('{{')),
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('{{')), [['', '{{'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('{{\\}}')), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('{{a}b}')), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('{{{a}}')), undefined);
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { TemplateParser } from '../inline';
|
|
3
|
-
import { union, some,
|
|
3
|
+
import { union, some, syntax, creator, precedence, surround, lazy } from '../../combinator';
|
|
4
|
+
import { optimize } from './link';
|
|
4
5
|
import { escsource, str } from '../source';
|
|
6
|
+
import { Rule } from '../context';
|
|
5
7
|
import { html } from 'typed-dom/dom';
|
|
6
8
|
import { unshift } from 'spica/array';
|
|
7
9
|
|
|
8
|
-
export const template: TemplateParser = lazy(() =>
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
export const template: TemplateParser = lazy(() => syntax(Rule.none, 2, surround(
|
|
11
|
+
'{{', some(union([bracket, escsource]), '}'), '}}', true,
|
|
12
|
+
([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest],
|
|
13
|
+
([, ns = [], rest], next) => next[0] === '}' ? undefined : optimize('{{', ns, rest, next))));
|
|
11
14
|
|
|
12
|
-
const bracket: TemplateParser.BracketParser = lazy(() => union([
|
|
15
|
+
const bracket: TemplateParser.BracketParser = lazy(() => creator(union([
|
|
13
16
|
surround(str('('), some(union([bracket, escsource]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
14
17
|
surround(str('['), some(union([bracket, escsource]), ']'), str(']'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
15
18
|
surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
16
19
|
surround(str('"'), precedence(8, some(escsource, /^"|^\\?\n/)), str('"'), true),
|
|
17
|
-
]));
|
|
20
|
+
])));
|
|
@@ -159,6 +159,7 @@ describe('Unit: parser/inline', () => {
|
|
|
159
159
|
assert.deepStrictEqual(inspect(parser('[[${]]}$')), [['', '[[', '<span class="math" translate="no" data-src="${]]}$">${]]}$</span>'], '']);
|
|
160
160
|
assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference"><span>""</span></sup>'], '']);
|
|
161
161
|
assert.deepStrictEqual(inspect(parser('[[a](b)]{c}')), [['<a href="c"><ruby>a<rp>(</rp><rt>b</rt><rp>)</rp></ruby></a>'], '']);
|
|
162
|
+
assert.deepStrictEqual(inspect(parser('[[[[[[[{a}')), [['', '[[[[[[[', '<a href="a">a</a>'], '']);
|
|
162
163
|
assert.deepStrictEqual(inspect(parser('<http://host>')), [['<', '<a href="http://host" target="_blank">http://host</a>', '>'], '']);
|
|
163
164
|
assert.deepStrictEqual(inspect(parser('[~http://host')), [['', '[', '~', '<a href="http://host" target="_blank">http://host</a>'], '']);
|
|
164
165
|
assert.deepStrictEqual(inspect(parser('[~a@b')), [['', '[', '~', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
@@ -167,7 +168,7 @@ describe('Unit: parser/inline', () => {
|
|
|
167
168
|
assert.deepStrictEqual(inspect(parser('[^a@b')), [['[^', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
168
169
|
assert.deepStrictEqual(inspect(parser('[#a*b\nc*]')), [['[', '<a href="/hashtags/a" class="hashtag">#a</a>', '<em>b<br>c</em>', ']'], '']);
|
|
169
170
|
assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), [['[', '<em>a<br>b</em>', ']', '<a href="/">/</a>'], '']);
|
|
170
|
-
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['', '[
|
|
171
|
+
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['[', '[', '<em>a<br>b</em>', ']', ']'], '']);
|
|
171
172
|
assert.deepStrictEqual(inspect(parser('"[% *"*"*')), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
|
|
172
173
|
assert.deepStrictEqual(inspect(parser('"[% "*"* %]')), [['"', '[%', ' ', '"', '*', '"', '*', ' ', '%', ']'], '']);
|
|
173
174
|
});
|
package/src/parser/locale.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Parser } from '../combinator/data/parser';
|
|
|
2
2
|
import { fmap } from '../combinator';
|
|
3
3
|
import { japanese } from './locale/ja';
|
|
4
4
|
import { html } from 'typed-dom/dom';
|
|
5
|
+
import { duffEach } from 'spica/duff';
|
|
5
6
|
|
|
6
7
|
export function localize<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
7
8
|
export function localize(parser: Parser<HTMLElement | string>): Parser<HTMLElement | string> {
|
|
@@ -10,13 +11,11 @@ export function localize(parser: Parser<HTMLElement | string>): Parser<HTMLEleme
|
|
|
10
11
|
const el = ns.length === 1 && typeof ns[0] === 'object'
|
|
11
12
|
? ns[0]
|
|
12
13
|
: html('div', ns);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
sb.firstChild!.remove();
|
|
19
|
-
}
|
|
14
|
+
duffEach(el.querySelectorAll('.linebreak:not(:empty)'), el => {
|
|
15
|
+
assert(el.firstChild!.textContent === ' ');
|
|
16
|
+
if (!check(el)) return;
|
|
17
|
+
el.firstChild!.remove();
|
|
18
|
+
});
|
|
20
19
|
return ns;
|
|
21
20
|
});
|
|
22
21
|
}
|
|
@@ -2,6 +2,7 @@ import { undefined, Infinity, Map, Node } from 'spica/global';
|
|
|
2
2
|
import { text } from '../inline/extension/indexee';
|
|
3
3
|
import { frag, html, define } from 'typed-dom/dom';
|
|
4
4
|
import { MultiMap } from 'spica/multimap';
|
|
5
|
+
import { duffEach, duffReduce } from 'spica/duff';
|
|
5
6
|
import { push } from 'spica/array';
|
|
6
7
|
|
|
7
8
|
export function* footnote(
|
|
@@ -12,7 +13,7 @@ export function* footnote(
|
|
|
12
13
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
13
14
|
// Bug: Firefox
|
|
14
15
|
//target.querySelectorAll(`:scope > .annotations`).forEach(el => el.remove());
|
|
15
|
-
target.querySelectorAll(`.annotations`)
|
|
16
|
+
duffEach(target.querySelectorAll(`.annotations`), el => el.parentNode === target && el.remove());
|
|
16
17
|
yield* reference(target, footnotes?.references, opts, bottom);
|
|
17
18
|
yield* annotation(target, footnotes?.annotations, opts, bottom);
|
|
18
19
|
return;
|
|
@@ -40,8 +41,9 @@ function build(
|
|
|
40
41
|
const titles = new Map<string, string>();
|
|
41
42
|
// Bug: Firefox
|
|
42
43
|
//const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
|
|
43
|
-
const splitters =
|
|
44
|
-
|
|
44
|
+
const splitters = duffReduce(target.querySelectorAll(splitter ?? '_'), (acc, el) =>
|
|
45
|
+
el.parentNode === target ? push(acc, [el]) : acc
|
|
46
|
+
, [] as Element[]);
|
|
45
47
|
let count = 0;
|
|
46
48
|
let total = 0;
|
|
47
49
|
let style: 'count' | 'abbr';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { TextParser, TxtParser, LinebreakParser } from '../source';
|
|
3
|
-
import { union,
|
|
3
|
+
import { union, creator, focus } from '../../combinator';
|
|
4
4
|
import { str } from './str';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
package/src/parser/util.ts
CHANGED
|
@@ -1,223 +1,3 @@
|
|
|
1
|
-
import { undefined } from 'spica/global';
|
|
2
|
-
import { MarkdownParser } from '../../markdown';
|
|
3
|
-
import { Parser, eval } from '../combinator/data/parser';
|
|
4
|
-
import { union, some, verify, convert, fmap } from '../combinator';
|
|
5
|
-
import { unsafehtmlentity } from './inline/htmlentity';
|
|
6
|
-
import { linebreak, unescsource } from './source';
|
|
7
|
-
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
8
|
-
import { memoize, reduce } from 'spica/memoize';
|
|
9
|
-
import { push } from 'spica/array';
|
|
10
|
-
|
|
11
|
-
export function clean<P extends Parser<unknown>>(parser: P): P;
|
|
12
|
-
export function clean<T>(parser: Parser<T, MarkdownParser.Context>): Parser<T, MarkdownParser.Context> {
|
|
13
|
-
const clean = memoize<MarkdownParser.Context, MarkdownParser.Context>(context => ({
|
|
14
|
-
resources: context.resources,
|
|
15
|
-
precedence: context.precedence,
|
|
16
|
-
delimiters: context.delimiters,
|
|
17
|
-
host: context.host,
|
|
18
|
-
url: context.url,
|
|
19
|
-
id: context.id,
|
|
20
|
-
header: context.header,
|
|
21
|
-
cache: context.caches,
|
|
22
|
-
}), new WeakMap());
|
|
23
|
-
return (source, context) =>
|
|
24
|
-
parser(source, context.syntax ? clean(context) : context);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const regBlankStart = new RegExp(
|
|
28
|
-
/^(?:\\?[^\S\n]|&IHN;|<wbr>)+/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`));
|
|
29
|
-
|
|
30
|
-
export function blankWith(delimiter: string | RegExp): RegExp;
|
|
31
|
-
export function blankWith(starting: '' | '\n', delimiter: string | RegExp): RegExp;
|
|
32
|
-
export function blankWith(starting: '' | '\n', delimiter?: string | RegExp): RegExp {
|
|
33
|
-
if (delimiter === undefined) return blankWith('', starting);
|
|
34
|
-
return new RegExp(String.raw
|
|
35
|
-
`^(?:(?=${
|
|
36
|
-
starting
|
|
37
|
-
})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>)${starting && '+'})?${
|
|
38
|
-
typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source
|
|
39
|
-
}`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function visualize<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
43
|
-
export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
44
|
-
const blankline = new RegExp(
|
|
45
|
-
/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr>)+$/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
46
|
-
'gm');
|
|
47
|
-
return union([
|
|
48
|
-
convert(
|
|
49
|
-
source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')),
|
|
50
|
-
verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
|
|
51
|
-
some(union([linebreak, unescsource])),
|
|
52
|
-
]);
|
|
53
|
-
}
|
|
54
|
-
function hasVisible(
|
|
55
|
-
nodes: readonly (HTMLElement | string)[],
|
|
56
|
-
{ syntax: { inline: { media = true } = {} } = {} }: MarkdownParser.Context = {},
|
|
57
|
-
): boolean {
|
|
58
|
-
for (let i = 0; i < nodes.length; ++i) {
|
|
59
|
-
const node = nodes[i];
|
|
60
|
-
if (typeof node === 'string') {
|
|
61
|
-
if (node && node.trimStart()) return true;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
if (node.innerText.trimStart()) return true;
|
|
65
|
-
if (media && (node.classList.contains('media') || node.getElementsByClassName('media')[0])) return true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function startLoose<P extends Parser<HTMLElement | string>>(parser: P, except?: string): P;
|
|
72
|
-
export function startLoose<T extends HTMLElement | string>(parser: Parser<T>, except?: string): Parser<T> {
|
|
73
|
-
return (source, context) =>
|
|
74
|
-
isStartLoose(source, context, except)
|
|
75
|
-
? parser(source, context)
|
|
76
|
-
: undefined;
|
|
77
|
-
}
|
|
78
|
-
const isStartLoose = reduce((source: string, context: MarkdownParser.Context, except?: string): boolean => {
|
|
79
|
-
return isStartTight(source.replace(regBlankStart, ''), context, except);
|
|
80
|
-
}, (source, _, except = '') => `${source}\x1E${except}`);
|
|
81
|
-
|
|
82
|
-
export function startTight<P extends Parser<unknown>>(parser: P, except?: string): P;
|
|
83
|
-
export function startTight<T>(parser: Parser<T>, except?: string): Parser<T> {
|
|
84
|
-
return (source, context) =>
|
|
85
|
-
isStartTight(source, context, except)
|
|
86
|
-
? parser(source, context)
|
|
87
|
-
: undefined;
|
|
88
|
-
}
|
|
89
|
-
const isStartTight = reduce((source: string, context: MarkdownParser.Context, except?: string): boolean => {
|
|
90
|
-
if (source === '') return true;
|
|
91
|
-
if (except && source.slice(0, except.length) === except) return false;
|
|
92
|
-
switch (source[0]) {
|
|
93
|
-
case ' ':
|
|
94
|
-
case ' ':
|
|
95
|
-
case '\t':
|
|
96
|
-
case '\n':
|
|
97
|
-
return false;
|
|
98
|
-
case '\\':
|
|
99
|
-
return source[1]?.trimStart() !== '';
|
|
100
|
-
case '&':
|
|
101
|
-
switch (true) {
|
|
102
|
-
case source.length > 2
|
|
103
|
-
&& source[1] !== ' '
|
|
104
|
-
&& eval(unsafehtmlentity(source, context))?.[0]?.trimStart() === '':
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return true;
|
|
108
|
-
case '<':
|
|
109
|
-
switch (true) {
|
|
110
|
-
case source.length >= 5
|
|
111
|
-
&& source[1] === 'w'
|
|
112
|
-
&& source.slice(0, 5) === '<wbr>':
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
116
|
-
default:
|
|
117
|
-
return source[0].trimStart() !== '';
|
|
118
|
-
}
|
|
119
|
-
}, (source, _, except = '') => `${source}\x1E${except}`);
|
|
120
|
-
|
|
121
|
-
export function isStartLooseNodes(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
122
|
-
if (nodes.length === 0) return true;
|
|
123
|
-
for (let i = 0; i < nodes.length; ++i) {
|
|
124
|
-
const node = nodes[i];
|
|
125
|
-
if (isVisible(node)) return true;
|
|
126
|
-
if (typeof node === 'object') {
|
|
127
|
-
if (node.tagName === 'BR') break;
|
|
128
|
-
if (node.className === 'linebreak') break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return false;
|
|
132
|
-
}
|
|
133
|
-
export function isStartTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
134
|
-
if (nodes.length === 0) return true;
|
|
135
|
-
return isVisible(nodes[0], 0);
|
|
136
|
-
}
|
|
137
|
-
//export function isEndTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
138
|
-
// if (nodes.length === 0) return true;
|
|
139
|
-
// return isVisible(nodes[nodes.length - 1], -1);
|
|
140
|
-
//}
|
|
141
|
-
function isVisible(node: HTMLElement | string, strpos?: number): boolean {
|
|
142
|
-
switch (typeof node) {
|
|
143
|
-
case 'string':
|
|
144
|
-
const char = node && strpos !== undefined
|
|
145
|
-
? node[strpos >= 0 ? strpos : node.length + strpos]
|
|
146
|
-
: node;
|
|
147
|
-
switch (char) {
|
|
148
|
-
case '':
|
|
149
|
-
case ' ':
|
|
150
|
-
case '\t':
|
|
151
|
-
case '\n':
|
|
152
|
-
return false;
|
|
153
|
-
default:
|
|
154
|
-
return char.trimStart() !== '';
|
|
155
|
-
}
|
|
156
|
-
default:
|
|
157
|
-
switch (node.tagName) {
|
|
158
|
-
case 'BR':
|
|
159
|
-
case 'WBR':
|
|
160
|
-
return false;
|
|
161
|
-
case 'SPAN':
|
|
162
|
-
return node.className !== 'linebreak';
|
|
163
|
-
default:
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function trimBlank<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
170
|
-
export function trimBlank<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
171
|
-
return trimBlankStart(trimBlankEnd(parser));
|
|
172
|
-
}
|
|
173
|
-
export function trimBlankStart<P extends Parser<unknown>>(parser: P): P;
|
|
174
|
-
export function trimBlankStart<T>(parser: Parser<T>): Parser<T> {
|
|
175
|
-
return convert(
|
|
176
|
-
reduce(source => source.replace(regBlankStart, '')),
|
|
177
|
-
parser);
|
|
178
|
-
}
|
|
179
|
-
export function trimBlankEnd<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
180
|
-
export function trimBlankEnd<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
181
|
-
return fmap(
|
|
182
|
-
parser,
|
|
183
|
-
trimNodeEnd);
|
|
184
|
-
}
|
|
185
|
-
export function trimNode<T extends HTMLElement | string>(nodes: T[]): T[] {
|
|
186
|
-
return trimNodeStart(trimNodeEnd(nodes));
|
|
187
|
-
}
|
|
188
|
-
function trimNodeStart<T extends HTMLElement | string>(nodes: T[]): T[] {
|
|
189
|
-
for (let node = nodes[0]; nodes.length > 0 && !isVisible(node = nodes[0], 0);) {
|
|
190
|
-
if (nodes.length === 1 && typeof node === 'object' && node.className === 'indexer') break;
|
|
191
|
-
if (typeof node === 'string') {
|
|
192
|
-
const pos = node.trimStart().length;
|
|
193
|
-
if (pos > 0) {
|
|
194
|
-
nodes[0] = node.slice(pos) as T;
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
nodes.shift();
|
|
199
|
-
}
|
|
200
|
-
return nodes;
|
|
201
|
-
}
|
|
202
|
-
function trimNodeEnd<T extends HTMLElement | string>(nodes: T[]): T[] {
|
|
203
|
-
const skip = nodes.length > 0 &&
|
|
204
|
-
typeof nodes[nodes.length - 1] === 'object' &&
|
|
205
|
-
nodes[nodes.length - 1]['className'] === 'indexer'
|
|
206
|
-
? [nodes.pop()!]
|
|
207
|
-
: [];
|
|
208
|
-
for (let node = nodes[0]; nodes.length > 0 && !isVisible(node = nodes[nodes.length - 1], -1);) {
|
|
209
|
-
if (typeof node === 'string') {
|
|
210
|
-
const pos = node.trimEnd().length;
|
|
211
|
-
if (pos > 0) {
|
|
212
|
-
nodes[nodes.length - 1] = node.slice(0, pos) as T;
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
nodes.pop();
|
|
217
|
-
}
|
|
218
|
-
return push(nodes, skip);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
1
|
export function stringify(nodes: readonly (HTMLElement | string)[]): string {
|
|
222
2
|
let acc = '';
|
|
223
3
|
for (let i = 0; i < nodes.length; ++i) {
|