securemark 0.295.7 → 0.295.9
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 +243 -298
- package/package.json +1 -1
- package/src/combinator/control/constraint/contract.ts +5 -21
- package/src/combinator/data/parser/context.ts +3 -1
- package/src/combinator/data/parser/sequence.ts +3 -3
- package/src/combinator/data/parser.ts +5 -2
- package/src/parser/api/normalize.ts +1 -1
- package/src/parser/block/extension/figbase.test.ts +3 -0
- package/src/parser/block/extension/figbase.ts +1 -1
- package/src/parser/block/paragraph.test.ts +2 -2
- package/src/parser/block/reply/cite.ts +2 -1
- package/src/parser/block/reply/quote.ts +2 -1
- package/src/parser/block/reply.ts +2 -1
- package/src/parser/inline/emphasis.ts +3 -3
- package/src/parser/inline/emstrong.ts +4 -4
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/extension/indexer.ts +3 -3
- package/src/parser/inline/extension/placeholder.ts +2 -2
- package/src/parser/inline/html.ts +2 -1
- package/src/parser/inline/htmlentity.test.ts +1 -1
- package/src/parser/inline/htmlentity.ts +10 -5
- package/src/parser/inline/italic.ts +2 -2
- package/src/parser/inline/link.ts +4 -2
- package/src/parser/inline/mark.ts +2 -2
- package/src/parser/inline/math.test.ts +10 -2
- package/src/parser/inline/math.ts +2 -2
- package/src/parser/inline/remark.ts +1 -1
- package/src/parser/inline/strong.ts +3 -3
- package/src/parser/node.ts +10 -0
- package/src/parser/source/str.ts +9 -7
- package/src/parser/source/text.ts +10 -42
- package/src/parser/visibility.ts +38 -69
- /package/src/combinator/data/{data.ts → node.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Parser, Input, List, Node, Context
|
|
2
|
-
import { matcher } from '../../../combinator';
|
|
1
|
+
import { Parser, Input, List, Node, Context } from '../../data/parser';
|
|
2
|
+
import { matcher, bind } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
//export function contract<P extends Parser>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
|
|
5
5
|
//export function contract<N>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<N>, cond: (nodes: readonly N[], rest: string) => boolean): Parser<N> {
|
|
@@ -11,32 +11,16 @@ export function validate<P extends Parser>(cond: ((input: Input<Parser.Context<P
|
|
|
11
11
|
export function validate<N>(pattern: string | RegExp | ((input: Input<Context>) => boolean), parser: Parser<N>): Parser<N> {
|
|
12
12
|
if (typeof pattern === 'function') return guard(pattern, parser);
|
|
13
13
|
const match = matcher(pattern, false);
|
|
14
|
-
return input =>
|
|
15
|
-
const { context } = input;
|
|
16
|
-
const { source, position } = context;
|
|
17
|
-
if (position === source.length) return;
|
|
18
|
-
if (!match(input)) return;
|
|
19
|
-
return parser(input);
|
|
20
|
-
};
|
|
14
|
+
return input => match(input) ? parser(input) : undefined;
|
|
21
15
|
}
|
|
22
16
|
|
|
23
17
|
function guard<P extends Parser>(f: (input: Input<Parser.Context<P>>) => boolean, parser: P): P;
|
|
24
18
|
function guard<N>(f: (input: Input<Context>) => boolean, parser: Parser<N>): Parser<N> {
|
|
25
|
-
return input =>
|
|
26
|
-
f(input)
|
|
27
|
-
? parser(input)
|
|
28
|
-
: undefined;
|
|
19
|
+
return input => f(input) ? parser(input) : undefined;
|
|
29
20
|
}
|
|
30
21
|
|
|
31
22
|
export function verify<P extends Parser>(parser: P, cond: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>) => boolean): P;
|
|
32
23
|
export function verify<N>(parser: Parser<N>, cond: (nodes: List<Node<N>>, context: Context) => boolean): Parser<N> {
|
|
33
24
|
assert(parser);
|
|
34
|
-
return
|
|
35
|
-
const { context } = input;
|
|
36
|
-
const { source, position } = context;
|
|
37
|
-
if (position === source.length) return;
|
|
38
|
-
const result = parser(input);
|
|
39
|
-
if (result && !cond(result, context)) return;
|
|
40
|
-
return result;
|
|
41
|
-
});
|
|
25
|
+
return bind(parser, (nodes, context) => cond(nodes, context) ? nodes : undefined)
|
|
42
26
|
}
|
|
@@ -159,7 +159,7 @@ export function constraint<N>(state: number, positive: boolean | Parser<N>, pars
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
export function matcher(pattern: string | RegExp, advance: boolean): Parser<string> {
|
|
162
|
+
export function matcher(pattern: string | RegExp, advance: boolean, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
|
|
163
163
|
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
164
164
|
const count = typeof pattern === 'object'
|
|
165
165
|
? /[^^\\*+][*+]/.test(pattern.source)
|
|
@@ -169,6 +169,7 @@ export function matcher(pattern: string | RegExp, advance: boolean): Parser<stri
|
|
|
169
169
|
return ({ context }) => {
|
|
170
170
|
const { source, position } = context;
|
|
171
171
|
if (!source.startsWith(pattern, position)) return;
|
|
172
|
+
if (verify?.(source, position, pattern.length) === false) return;
|
|
172
173
|
if (advance) {
|
|
173
174
|
context.position += pattern.length;
|
|
174
175
|
}
|
|
@@ -182,6 +183,7 @@ export function matcher(pattern: string | RegExp, advance: boolean): Parser<stri
|
|
|
182
183
|
if (!pattern.test(source)) return;
|
|
183
184
|
const src = source.slice(position, pattern.lastIndex);
|
|
184
185
|
count && consume(src.length, context);
|
|
186
|
+
if (verify?.(source, position, src.length) === false) return;
|
|
185
187
|
if (advance) {
|
|
186
188
|
context.position += src.length;
|
|
187
189
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Parser, List, Node, Context } from '../parser';
|
|
1
|
+
import { Parser, List, Node, Context, failsafe } from '../parser';
|
|
2
2
|
|
|
3
3
|
export function sequence<P extends Parser>(parsers: Parser.SubParsers<P>): Parser.SubNode<P> extends Parser.Node<P> ? P : Parser<Parser.SubNode<P>, Parser.Context<P>, Parser.SubParsers<P>>;
|
|
4
4
|
export function sequence<N, D extends Parser<N>[]>(parsers: D): Parser<N, Context, D> {
|
|
5
5
|
assert(parsers.every(f => f));
|
|
6
6
|
if (parsers.length === 1) return parsers[0];
|
|
7
|
-
return input => {
|
|
7
|
+
return failsafe(input => {
|
|
8
8
|
const { context } = input;
|
|
9
9
|
const { source } = context;
|
|
10
10
|
let nodes: List<Node<N>> | undefined;
|
|
@@ -16,5 +16,5 @@ export function sequence<N, D extends Parser<N>[]>(parsers: D): Parser<N, Contex
|
|
|
16
16
|
nodes = nodes?.import(result) ?? result;
|
|
17
17
|
}
|
|
18
18
|
return nodes;
|
|
19
|
-
};
|
|
19
|
+
});
|
|
20
20
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { List } from './
|
|
1
|
+
import { List } from './node';
|
|
2
2
|
import { Delimiters } from './delimiter';
|
|
3
3
|
|
|
4
4
|
export type Parser<N = unknown, C extends Context = Context, D extends Parser<unknown, C>[] = any>
|
|
@@ -20,7 +20,10 @@ export type Result<N, C extends Context = Context, D extends Parser<unknown, C>[
|
|
|
20
20
|
| undefined;
|
|
21
21
|
export { List };
|
|
22
22
|
export class Node<N> implements List.Node {
|
|
23
|
-
constructor(
|
|
23
|
+
constructor(
|
|
24
|
+
public value: N,
|
|
25
|
+
public flags: number = 0,
|
|
26
|
+
) {
|
|
24
27
|
}
|
|
25
28
|
public next?: this = undefined;
|
|
26
29
|
public prev?: this = undefined;
|
|
@@ -13,10 +13,13 @@ describe('Unit: parser/block/extension/figbase', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('$-0.', new Context())), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('$-0.1', new Context())), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('$-1', new Context())), undefined);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser, input('$-0 0', new Context())), undefined);
|
|
16
17
|
assert.deepStrictEqual(inspect(parser, input('$-0\n 0', new Context())), undefined);
|
|
17
18
|
assert.deepStrictEqual(inspect(parser, input('$-name', new Context())), undefined);
|
|
18
19
|
assert.deepStrictEqual(inspect(parser, input('$-name-0', new Context())), undefined);
|
|
19
20
|
assert.deepStrictEqual(inspect(parser, input('$group-0', new Context())), undefined);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser, input('$-0]', new Context())), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser, input('[$-0', new Context())), undefined);
|
|
20
23
|
assert.deepStrictEqual(inspect(parser, input(' [$-0]', new Context())), undefined);
|
|
21
24
|
});
|
|
22
25
|
|
|
@@ -5,7 +5,7 @@ import { label } from '../../inline/extension/label';
|
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
export const figbase: ExtensionParser.FigbaseParser = block(fmap(
|
|
8
|
-
validate(/\[?\$-(?:[0-9]+\.)*0\]?
|
|
8
|
+
validate(/\[?\$-(?:[0-9]+\.)*0\]?[^\S\n]*(?:$|\n)/y,
|
|
9
9
|
line(union([label]))),
|
|
10
10
|
([{ value: el }]) => {
|
|
11
11
|
const label = el.getAttribute('data-label')!;
|
|
@@ -22,8 +22,8 @@ describe('Unit: parser/block/paragraph', () => {
|
|
|
22
22
|
assert.deepStrictEqual(inspect(parser, input('a\\ \n', new Context())), [['<p>a</p>'], '']);
|
|
23
23
|
assert.deepStrictEqual(inspect(parser, input('a\\\n', new Context())), [['<p>a</p>'], '']);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser, input('a\\\nb', new Context())), [['<p>a<br>b</p>'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser, input('a
b', new Context())), [['<p>a b</p>'], '']);
|
|
26
|
-
assert.deepStrictEqual(inspect(parser, input('	&
|
|
25
|
+
assert.deepStrictEqual(inspect(parser, input('a
b', new Context())), [['<p>a<span class="invalid">&NewLine;</span>b</p>'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('	 ', new Context())), [['<p>&Tab;</p>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser, input('<wbr>', new Context())), [['<p><wbr></p>'], '']);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser, input('<wbr>\n', new Context())), [['<p><wbr></p>'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser, input('<wbr>\na', new Context())), [['<p><wbr><br>a</p>'], '']);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReplyParser } from '../../block';
|
|
2
2
|
import { List, Node } from '../../../combinator/data/parser';
|
|
3
|
+
import { Flag } from '../../node';
|
|
3
4
|
import { union, line, focus, open, fmap } from '../../../combinator';
|
|
4
5
|
import { anchor } from '../../inline/autolink/anchor';
|
|
5
6
|
import { str } from '../../source';
|
|
@@ -33,6 +34,6 @@ export const cite: ReplyParser.CiteParser = line(fmap(
|
|
|
33
34
|
? define(node, { 'data-depth': `${quotes.length + 1}` }, node.innerText.slice(1))
|
|
34
35
|
: node.slice(1),
|
|
35
36
|
]))),
|
|
36
|
-
new Node(html('br')),
|
|
37
|
+
new Node(html('br'), Flag.invisible),
|
|
37
38
|
]);
|
|
38
39
|
}));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReplyParser } from '../../block';
|
|
2
2
|
import { List, Node } from '../../../combinator/data/parser';
|
|
3
|
+
import { Flag } from '../../node';
|
|
3
4
|
import { union, some, block, validate, rewrite, convert, lazy, fmap } from '../../../combinator';
|
|
4
5
|
import { math } from '../../inline/math';
|
|
5
6
|
import { autolink } from '../../inline/autolink';
|
|
@@ -21,7 +22,7 @@ export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(
|
|
|
21
22
|
unescsource,
|
|
22
23
|
])))),
|
|
23
24
|
(ns, { source, position }) => new List([
|
|
24
|
-
new Node(source[position - 1] === '\n' ? ns.pop()!.value as HTMLBRElement : html('br')),
|
|
25
|
+
new Node(source[position - 1] === '\n' ? ns.pop()!.value as HTMLBRElement : html('br'), Flag.invisible),
|
|
25
26
|
new Node(html('span', { class: 'quote' }, defrag(unwrap(ns)))),
|
|
26
27
|
].reverse())),
|
|
27
28
|
false));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReplyParser } from '../block';
|
|
2
2
|
import { List, Node } from '../../combinator/data/parser';
|
|
3
|
+
import { Flag } from '../node';
|
|
3
4
|
import { union, some, block, validate, rewrite, fmap } from '../../combinator';
|
|
4
5
|
import { cite, syntax as csyntax } from './reply/cite';
|
|
5
6
|
import { quote, syntax as qsyntax } from './reply/quote';
|
|
@@ -20,6 +21,6 @@ export const reply: ReplyParser = block(validate(csyntax, fmap(
|
|
|
20
21
|
visualize(fmap(some(inline), (ns, { source, position }) =>
|
|
21
22
|
source[position - 1] === '\n'
|
|
22
23
|
? ns
|
|
23
|
-
: ns.push(new Node(html('br'))) && ns)))
|
|
24
|
+
: ns.push(new Node(html('br'), Flag.invisible)) && ns)))
|
|
24
25
|
])),
|
|
25
26
|
ns => new List([new Node(html('p', defrag(unwrap(trimBlankNodeEnd(ns)))))]))));
|
|
@@ -5,14 +5,14 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { strong } from './strong';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
9
9
|
import { unwrap } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const emphasis: EmphasisParser = lazy(() => surround(
|
|
13
|
-
str(
|
|
13
|
+
str('*', (source, position, range) => !source.startsWith('*', position + range)),
|
|
14
14
|
precedence(0, recursion(Recursion.inline,
|
|
15
|
-
|
|
15
|
+
beforeNonblank(some(union([
|
|
16
16
|
some(inline, '*', afterNonblank),
|
|
17
17
|
strong,
|
|
18
18
|
]))))),
|
|
@@ -5,8 +5,8 @@ import { union, some, recursion, precedence, surround, lazy, bind } from '../../
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { strong } from './strong';
|
|
7
7
|
import { emphasis } from './emphasis';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { strs } from '../source';
|
|
9
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
10
10
|
import { unwrap, repeat } from '../util';
|
|
11
11
|
import { html, defrag } from 'typed-dom/dom';
|
|
12
12
|
|
|
@@ -25,8 +25,8 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
|
|
|
25
25
|
export const emstrong: EmStrongParser = lazy(() =>
|
|
26
26
|
precedence(0, recursion(Recursion.inline, repeat('***', surround(
|
|
27
27
|
'',
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
beforeNonblank(some(union([some(inline, '*', afterNonblank)]))),
|
|
29
|
+
strs('*', 3),
|
|
30
30
|
false, [],
|
|
31
31
|
([, bs, cs], context): Result<Parser.Node<EmStrongParser>, Parser.Context<EmStrongParser>> => {
|
|
32
32
|
assert(cs.length === 1);
|
|
@@ -6,7 +6,7 @@ import { inline } from '../../inline';
|
|
|
6
6
|
import { indexee, identity } from './indexee';
|
|
7
7
|
import { unsafehtmlentity } from '../htmlentity';
|
|
8
8
|
import { txt, str } from '../../source';
|
|
9
|
-
import {
|
|
9
|
+
import { beforeNonblank, trimBlankNodeEnd } from '../../visibility';
|
|
10
10
|
import { unwrap } from '../../util';
|
|
11
11
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ import IndexParser = ExtensionParser.IndexParser;
|
|
|
15
15
|
export const index: IndexParser = lazy(() => constraint(State.index, fmap(indexee(surround(
|
|
16
16
|
str('[#'),
|
|
17
17
|
precedence(1, state(State.linkers,
|
|
18
|
-
|
|
18
|
+
beforeNonblank(
|
|
19
19
|
some(inits([
|
|
20
20
|
inline,
|
|
21
21
|
signature,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ExtensionParser } from '../../inline';
|
|
2
2
|
import { List, Node } from '../../../combinator/data/parser';
|
|
3
|
-
import { union, focus, surround } from '../../../combinator';
|
|
3
|
+
import { union, validate, focus, surround } from '../../../combinator';
|
|
4
4
|
import { signature } from './index';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
@@ -10,10 +10,10 @@ import { html } from 'typed-dom/dom';
|
|
|
10
10
|
// テキストまたはインデクスを付けて同期が必要な機会を減らすのが
|
|
11
11
|
// 継続的編集において最も簡便となる。
|
|
12
12
|
|
|
13
|
-
export const indexer: ExtensionParser.IndexerParser = surround(
|
|
13
|
+
export const indexer: ExtensionParser.IndexerParser = validate(' [|', surround(
|
|
14
14
|
/ \[(?=\|\S)/y,
|
|
15
15
|
union([
|
|
16
16
|
signature,
|
|
17
17
|
focus(/\|(?=\])/y, () => new List([new Node(html('span', { class: 'indexer', 'data-index': '' }))])),
|
|
18
18
|
]),
|
|
19
|
-
/\][^\S\n]*(?:$|\n)/y);
|
|
19
|
+
/\][^\S\n]*(?:$|\n)/y));
|
|
@@ -4,7 +4,7 @@ import { List, Node } from '../../../combinator/data/parser';
|
|
|
4
4
|
import { union, some, recursion, precedence, surround, lazy } from '../../../combinator';
|
|
5
5
|
import { inline } from '../../inline';
|
|
6
6
|
import { str } from '../../source';
|
|
7
|
-
import {
|
|
7
|
+
import { beforeNonblank } from '../../visibility';
|
|
8
8
|
import { invalid } from '../../util';
|
|
9
9
|
import { html } from 'typed-dom/dom';
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surroun
|
|
|
16
16
|
// ^はabbrで使用済みだが^:などのようにして分離使用可能
|
|
17
17
|
str(/\[[:^|]/y),
|
|
18
18
|
precedence(1, recursion(Recursion.inline,
|
|
19
|
-
|
|
19
|
+
beforeNonblank(some(union([inline]), ']', [[']', 1]])))),
|
|
20
20
|
str(']'),
|
|
21
21
|
false,
|
|
22
22
|
[3 | Backtrack.common],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HTMLParser } from '../inline';
|
|
2
2
|
import { Recursion } from '../context';
|
|
3
3
|
import { List, Node, Context } from '../../combinator/data/parser';
|
|
4
|
+
import { Flag } from '../node';
|
|
4
5
|
import { union, some, recursion, precedence, validate, surround, open, match, lazy } from '../../combinator';
|
|
5
6
|
import { inline } from '../inline';
|
|
6
7
|
import { str } from '../source';
|
|
@@ -28,7 +29,7 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
|
|
|
28
29
|
open(str(/ ?/y), str('>'), true),
|
|
29
30
|
true, [],
|
|
30
31
|
([as, bs = new List(), cs], context) =>
|
|
31
|
-
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
|
|
32
|
+
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context), as.head!.value === '<wbr' ? Flag.invisible : Flag.none)]),
|
|
32
33
|
([as, bs = new List()], context) =>
|
|
33
34
|
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
|
|
34
35
|
match(
|
|
@@ -33,11 +33,11 @@ describe('Unit: parser/inline/htmlentity', () => {
|
|
|
33
33
|
assert.deepStrictEqual(inspect(parser, input('"', new Context())), [['&'], '#X22;']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser, input('ആ', new Context())), [['&'], '#XD06;']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser, input('ಫ', new Context())), [['&'], '#xcab;']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser, input('
', new Context())), [['<span class="invalid">&NewLine;</span>'], '']);
|
|
36
37
|
assert.deepStrictEqual(inspect(parser, input(' &', new Context())), undefined);
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
it('entity', () => {
|
|
40
|
-
assert.deepStrictEqual(inspect(parser, input('
', new Context())), [[' '], '']);
|
|
41
41
|
assert.deepStrictEqual(inspect(parser, input(' ', new Context())), [['\u00A0'], '']);
|
|
42
42
|
assert.deepStrictEqual(inspect(parser, input('&', new Context())), [['&'], '']);
|
|
43
43
|
assert.deepStrictEqual(inspect(parser, input('©', new Context())), [['©'], '']);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { HTMLEntityParser, UnsafeHTMLEntityParser } from '../inline';
|
|
2
2
|
import { Backtrack } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
+
import { Flag, isinvisibleHTMLEntityName } from '../node';
|
|
4
5
|
import { union, surround, fmap } from '../../combinator';
|
|
5
6
|
import { str } from '../source';
|
|
6
7
|
import { invalid } from '../util';
|
|
@@ -11,15 +12,19 @@ export const unsafehtmlentity: UnsafeHTMLEntityParser = surround(
|
|
|
11
12
|
false,
|
|
12
13
|
[3 | Backtrack.unescapable],
|
|
13
14
|
([as, bs, cs]) =>
|
|
14
|
-
new List([
|
|
15
|
+
new List([
|
|
16
|
+
new Node(
|
|
17
|
+
parser(as.head!.value + bs.head!.value + cs.head!.value),
|
|
18
|
+
isinvisibleHTMLEntityName(bs.head!.value) ? Flag.invisible : Flag.none)
|
|
19
|
+
]),
|
|
15
20
|
([as, bs]) =>
|
|
16
21
|
new List([new Node(as.head!.value + (bs?.head?.value ?? ''))]));
|
|
17
22
|
|
|
18
23
|
export const htmlentity: HTMLEntityParser = fmap(
|
|
19
24
|
union([unsafehtmlentity]),
|
|
20
|
-
([{ value }]) => new List([
|
|
21
|
-
length === 1 || value.at(-1) !== ';'
|
|
22
|
-
? new Node(value)
|
|
25
|
+
([{ value, flags }]) => new List([
|
|
26
|
+
value.length === 1 || value.at(-1) !== ';'
|
|
27
|
+
? new Node(value, flags)
|
|
23
28
|
: new Node(html('span', {
|
|
24
29
|
class: 'invalid',
|
|
25
30
|
...invalid('htmlentity', 'syntax', 'Invalid HTML entity'),
|
|
@@ -27,7 +32,7 @@ export const htmlentity: HTMLEntityParser = fmap(
|
|
|
27
32
|
]));
|
|
28
33
|
|
|
29
34
|
const parser = (el => (entity: string): string => {
|
|
30
|
-
if (entity === '
') return
|
|
35
|
+
if (entity === '
') return entity;
|
|
31
36
|
el.innerHTML = entity;
|
|
32
37
|
return el.textContent!;
|
|
33
38
|
})(html('span'));
|
|
@@ -3,7 +3,7 @@ import { Recursion, Command } from '../context';
|
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
4
|
import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
|
-
import {
|
|
6
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
7
7
|
import { unwrap, repeat } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
13
13
|
export const italic: ItalicParser = lazy(() =>
|
|
14
14
|
precedence(0, recursion(Recursion.inline, repeat('///', surround(
|
|
15
15
|
'',
|
|
16
|
-
|
|
16
|
+
beforeNonblank(some(union([inline]), '///', afterNonblank)),
|
|
17
17
|
'///',
|
|
18
18
|
false, [],
|
|
19
19
|
([, bs], { buffer }) => buffer.import(bs),
|
|
@@ -43,7 +43,9 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => bind(
|
|
|
43
43
|
bs && as.import(bs).push(new Node(Command.Cancel)) && as)),
|
|
44
44
|
]),
|
|
45
45
|
([{ value: content }, { value: params = undefined } = {}], context) => {
|
|
46
|
-
if (context.state & State.link) return new List([
|
|
46
|
+
if (context.state & State.link) return new List([
|
|
47
|
+
new Node(context.source.slice(context.position - context.range, context.position).replace(/\\($|.)/g, '$1'))
|
|
48
|
+
]);
|
|
47
49
|
if (content.last!.value === Command.Separator) {
|
|
48
50
|
content.pop();
|
|
49
51
|
if (params === undefined) {
|
|
@@ -88,7 +90,7 @@ export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State
|
|
|
88
90
|
new List([new Node(parse(content, params as List<Node<string>>, context))])))));
|
|
89
91
|
|
|
90
92
|
export const uri: LinkParser.ParameterParser.UriParser = union([
|
|
91
|
-
open(
|
|
93
|
+
open(' ', str(/\S+/y)),
|
|
92
94
|
str(/[^\s{}]+/y),
|
|
93
95
|
]);
|
|
94
96
|
|
|
@@ -4,14 +4,14 @@ import { List, Node } from '../../combinator/data/parser';
|
|
|
4
4
|
import { union, some, recursion, precedence, state, surround, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { identity, signature } from './extension/indexee';
|
|
7
|
-
import {
|
|
7
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
8
8
|
import { unwrap, repeat } from '../util';
|
|
9
9
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const mark: MarkParser = lazy(() =>
|
|
12
12
|
precedence(0, recursion(Recursion.inline, repeat('==', surround(
|
|
13
13
|
'',
|
|
14
|
-
|
|
14
|
+
beforeNonblank(state(State.mark, some(union([inline]), '==', afterNonblank))),
|
|
15
15
|
'==',
|
|
16
16
|
false, [],
|
|
17
17
|
([, bs], { buffer }) => buffer.import(bs),
|
|
@@ -14,6 +14,8 @@ describe('Unit: parser/inline/math', () => {
|
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('$$', new Context())), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('$$$', new Context())), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('$0 $', new Context())), undefined);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser, input('$0\\ $', new Context())), undefined);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser, input('$0\\\n$', new Context())), undefined);
|
|
17
19
|
assert.deepStrictEqual(inspect(parser, input('$-0, $-1', new Context())), undefined);
|
|
18
20
|
assert.deepStrictEqual(inspect(parser, input('$-0 and $-1', new Context())), undefined);
|
|
19
21
|
assert.deepStrictEqual(inspect(parser, input('$-0と$-1', new Context())), undefined);
|
|
@@ -38,9 +40,13 @@ describe('Unit: parser/inline/math', () => {
|
|
|
38
40
|
assert.deepStrictEqual(inspect(parser, input('$a$b', new Context())), undefined);
|
|
39
41
|
assert.deepStrictEqual(inspect(parser, input('$a$b$', new Context())), undefined);
|
|
40
42
|
assert.deepStrictEqual(inspect(parser, input('$ $', new Context())), undefined);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser, input('$\\ $', new Context())), undefined);
|
|
41
44
|
assert.deepStrictEqual(inspect(parser, input('$ a$', new Context())), undefined);
|
|
42
45
|
assert.deepStrictEqual(inspect(parser, input('$ a $', new Context())), undefined);
|
|
43
46
|
assert.deepStrictEqual(inspect(parser, input('$\n$', new Context())), undefined);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser, input('$\\\n$', new Context())), undefined);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser, input('$a\nb$', new Context())), undefined);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser, input('$a\\\nb$', new Context())), undefined);
|
|
44
50
|
assert.deepStrictEqual(inspect(parser, input('$a\\$\nb$', new Context())), undefined);
|
|
45
51
|
assert.deepStrictEqual(inspect(parser, input('$a\\$\\\nb$', new Context())), undefined);
|
|
46
52
|
assert.deepStrictEqual(inspect(parser, input('$`$', new Context())), undefined);
|
|
@@ -74,9 +80,12 @@ describe('Unit: parser/inline/math', () => {
|
|
|
74
80
|
assert.deepStrictEqual(inspect(parser, input('${a}b$', new Context())), undefined);
|
|
75
81
|
assert.deepStrictEqual(inspect(parser, input('${a}b{c}$', new Context())), undefined);
|
|
76
82
|
assert.deepStrictEqual(inspect(parser, input('${a}{b}$', new Context())), undefined);
|
|
77
|
-
assert.deepStrictEqual(inspect(parser, input('${$}$', new Context())), undefined);
|
|
78
83
|
assert.deepStrictEqual(inspect(parser, input('${\\}$', new Context())), undefined);
|
|
79
84
|
assert.deepStrictEqual(inspect(parser, input('${\n}$', new Context())), undefined);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser, input('${\\\n}$', new Context())), undefined);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser, input('${a\nb}$', new Context())), undefined);
|
|
87
|
+
assert.deepStrictEqual(inspect(parser, input('${a\\\nb}$', new Context())), undefined);
|
|
88
|
+
assert.deepStrictEqual(inspect(parser, input('${$}$', new Context())), undefined);
|
|
80
89
|
assert.deepStrictEqual(inspect(parser, input('${a\\$\nb}$', new Context())), undefined);
|
|
81
90
|
assert.deepStrictEqual(inspect(parser, input('${a\\$\\\nb}$', new Context())), undefined);
|
|
82
91
|
assert.deepStrictEqual(inspect(parser, input('$\\begin$', new Context())), [['<span class="invalid" translate="no">$\\begin$</span>'], '']);
|
|
@@ -109,7 +118,6 @@ describe('Unit: parser/inline/math', () => {
|
|
|
109
118
|
assert.deepStrictEqual(inspect(parser, input('$a$[A](a)', new Context())), [['<span class="math" translate="no" data-src="$a$">$a$</span>'], '[A](a)']);
|
|
110
119
|
assert.deepStrictEqual(inspect(parser, input('$A$', new Context())), [['<span class="math" translate="no" data-src="$A$">$A$</span>'], '']);
|
|
111
120
|
assert.deepStrictEqual(inspect(parser, input('$-a$', new Context())), [['<span class="math" translate="no" data-src="$-a$">$-a$</span>'], '']);
|
|
112
|
-
assert.deepStrictEqual(inspect(parser, input('$\\ $', new Context())), [['<span class="math" translate="no" data-src="$\\ $">$\\ $</span>'], '']);
|
|
113
121
|
assert.deepStrictEqual(inspect(parser, input('$\\$$', new Context())), [['<span class="math" translate="no" data-src="$\\$$">$\\$$</span>'], '']);
|
|
114
122
|
assert.deepStrictEqual(inspect(parser, input('$\\Pi$', new Context())), [['<span class="math" translate="no" data-src="$\\Pi$">$\\Pi$</span>'], '']);
|
|
115
123
|
assert.deepStrictEqual(inspect(parser, input('$\\ 0$', new Context())), [['<span class="math" translate="no" data-src="$\\ 0$">$\\ 0$</span>'], '']);
|
|
@@ -19,10 +19,10 @@ export const math: MathParser = lazy(() => rewrite(
|
|
|
19
19
|
surround(
|
|
20
20
|
/\$(?![\s{}])/y,
|
|
21
21
|
precedence(2, some(union([
|
|
22
|
-
some(escsource,
|
|
22
|
+
some(escsource, /\$|[`"{}\n]/y),
|
|
23
23
|
precedence(4, bracket),
|
|
24
24
|
]))),
|
|
25
|
-
|
|
25
|
+
/(?<!\s)\$(?![-0-9A-Za-z])/y,
|
|
26
26
|
false,
|
|
27
27
|
[3 | Backtrack.escapable]),
|
|
28
28
|
]),
|
|
@@ -11,7 +11,7 @@ export const remark: RemarkParser = lazy(() => fallback(surround(
|
|
|
11
11
|
str(/\[%(?=[ \n])/y),
|
|
12
12
|
precedence(3, recursion(Recursion.inline,
|
|
13
13
|
some(union([inline]), /[ \n]%\]/y, [[/[ \n]%\]/y, 3]]))),
|
|
14
|
-
close(text, str(
|
|
14
|
+
close(text, str('%]')),
|
|
15
15
|
true, [],
|
|
16
16
|
([as, bs = new List(), cs]) => new List([
|
|
17
17
|
new Node(html('span', { class: 'remark' }, [
|
|
@@ -5,14 +5,14 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { emphasis } from './emphasis';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
9
9
|
import { unwrap } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const strong: StrongParser = lazy(() => surround(
|
|
13
|
-
str(
|
|
13
|
+
str('**', (source, position, range) => !source.startsWith('*', position + range)),
|
|
14
14
|
precedence(0, recursion(Recursion.inline,
|
|
15
|
-
|
|
15
|
+
beforeNonblank(some(union([
|
|
16
16
|
some(inline, '*', afterNonblank),
|
|
17
17
|
emphasis,
|
|
18
18
|
]))))),
|
package/src/parser/source/str.ts
CHANGED
|
@@ -2,21 +2,23 @@ import { StrParser } from '../source';
|
|
|
2
2
|
import { Parser, List, Node } from '../../combinator/data/parser';
|
|
3
3
|
import { matcher } from '../../combinator';
|
|
4
4
|
|
|
5
|
-
export function str(pattern: string | RegExp): StrParser;
|
|
6
|
-
export function str(pattern: string | RegExp): Parser<string> {
|
|
7
|
-
return matcher(pattern, true);
|
|
5
|
+
export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): StrParser;
|
|
6
|
+
export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
|
|
7
|
+
return matcher(pattern, true, verify);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function strs(pattern: string): StrParser;
|
|
11
|
-
export function strs(pattern: string): Parser<string> {
|
|
10
|
+
export function strs(pattern: string, limit?: number): StrParser;
|
|
11
|
+
export function strs(pattern: string, limit: number = -1): Parser<string> {
|
|
12
12
|
assert(pattern);
|
|
13
13
|
return ({ context }) => {
|
|
14
14
|
const { source } = context;
|
|
15
15
|
let acc = '';
|
|
16
|
-
for (; context.position < source.length && source.startsWith(pattern, context.position);) {
|
|
16
|
+
for (let i = 0; i !== limit && context.position < source.length && source.startsWith(pattern, context.position); ++i) {
|
|
17
17
|
acc += pattern;
|
|
18
18
|
context.position += pattern.length;
|
|
19
19
|
}
|
|
20
|
-
return
|
|
20
|
+
return acc
|
|
21
|
+
? new List([new Node(acc)])
|
|
22
|
+
: undefined;
|
|
21
23
|
};
|
|
22
24
|
}
|