securemark 0.293.4 → 0.294.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.js +868 -564
- package/markdown.d.ts +13 -13
- package/package.json +3 -3
- package/src/combinator/control/constraint/block.test.ts +6 -6
- package/src/combinator/control/constraint/contract.ts +3 -3
- package/src/combinator/control/constraint/line.test.ts +7 -7
- package/src/combinator/control/constraint/line.ts +1 -1
- package/src/combinator/control/manipulation/clear.ts +2 -3
- package/src/combinator/control/manipulation/convert.ts +2 -2
- package/src/combinator/control/manipulation/duplicate.ts +4 -5
- package/src/combinator/control/manipulation/fence.ts +2 -2
- package/src/combinator/control/manipulation/indent.test.ts +2 -2
- package/src/combinator/control/manipulation/indent.ts +4 -4
- package/src/combinator/control/manipulation/reverse.ts +2 -2
- package/src/combinator/control/manipulation/scope.ts +3 -4
- package/src/combinator/control/manipulation/surround.ts +14 -15
- package/src/combinator/control/monad/bind.ts +6 -6
- package/src/combinator/control/monad/fmap.ts +7 -7
- package/src/combinator/data/data.ts +135 -0
- package/src/combinator/data/parser/context.test.ts +16 -15
- package/src/combinator/data/parser/context.ts +5 -4
- package/src/combinator/data/parser/inits.ts +6 -7
- package/src/combinator/data/parser/sequence.test.ts +3 -3
- package/src/combinator/data/parser/sequence.ts +6 -7
- package/src/combinator/data/parser/some.test.ts +3 -3
- package/src/combinator/data/parser/some.ts +4 -4
- package/src/combinator/data/parser/subsequence.test.ts +4 -4
- 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 +3 -3
- package/src/combinator/data/parser.ts +16 -7
- package/src/debug.test.ts +6 -5
- package/src/parser/api/bind.ts +6 -8
- package/src/parser/api/header.ts +1 -1
- package/src/parser/api/normalize.ts +2 -4
- package/src/parser/api/parse.ts +3 -1
- package/src/parser/block/blockquote.ts +6 -4
- package/src/parser/block/codeblock.ts +8 -7
- package/src/parser/block/dlist.ts +9 -8
- package/src/parser/block/extension/aside.ts +27 -21
- package/src/parser/block/extension/example.ts +29 -26
- package/src/parser/block/extension/fig.ts +1 -1
- package/src/parser/block/extension/figbase.ts +6 -5
- package/src/parser/block/extension/figure.ts +23 -19
- package/src/parser/block/extension/message.ts +35 -24
- package/src/parser/block/extension/placeholder.ts +17 -13
- package/src/parser/block/extension/table.ts +47 -40
- package/src/parser/block/heading.test.ts +3 -12
- package/src/parser/block/heading.ts +12 -8
- package/src/parser/block/ilist.ts +13 -12
- package/src/parser/block/mathblock.ts +21 -17
- package/src/parser/block/mediablock.ts +7 -5
- package/src/parser/block/olist.ts +15 -5
- package/src/parser/block/pagebreak.ts +2 -1
- package/src/parser/block/paragraph.ts +3 -1
- package/src/parser/block/reply/cite.ts +20 -15
- package/src/parser/block/reply/quote.ts +9 -7
- package/src/parser/block/reply.ts +7 -3
- package/src/parser/block/sidefence.ts +8 -7
- package/src/parser/block/table.ts +23 -22
- package/src/parser/block/ulist.ts +16 -12
- package/src/parser/block.ts +7 -6
- package/src/parser/header.test.ts +3 -1
- package/src/parser/header.ts +20 -20
- package/src/parser/inline/annotation.ts +3 -1
- package/src/parser/inline/autolink/account.ts +3 -2
- package/src/parser/inline/autolink/anchor.ts +3 -2
- package/src/parser/inline/autolink/channel.ts +5 -4
- package/src/parser/inline/autolink/email.ts +4 -3
- package/src/parser/inline/autolink/hashnum.ts +3 -2
- package/src/parser/inline/autolink/hashtag.ts +4 -3
- package/src/parser/inline/autolink/url.ts +7 -6
- package/src/parser/inline/bracket.ts +16 -15
- package/src/parser/inline/code.ts +5 -4
- package/src/parser/inline/deletion.ts +5 -5
- package/src/parser/inline/emphasis.ts +4 -3
- package/src/parser/inline/emstrong.test.ts +18 -18
- package/src/parser/inline/emstrong.ts +39 -30
- package/src/parser/inline/extension/index.ts +22 -19
- package/src/parser/inline/extension/indexee.ts +2 -2
- package/src/parser/inline/extension/indexer.ts +2 -1
- package/src/parser/inline/extension/label.ts +7 -3
- package/src/parser/inline/extension/placeholder.ts +6 -6
- package/src/parser/inline/html.ts +27 -28
- package/src/parser/inline/htmlentity.ts +9 -8
- package/src/parser/inline/insertion.ts +5 -5
- package/src/parser/inline/italic.ts +5 -5
- package/src/parser/inline/link.ts +36 -38
- package/src/parser/inline/mark.ts +7 -7
- package/src/parser/inline/math.ts +5 -4
- package/src/parser/inline/media.ts +33 -32
- package/src/parser/inline/reference.ts +19 -20
- package/src/parser/inline/remark.ts +11 -11
- package/src/parser/inline/ruby.ts +50 -53
- package/src/parser/inline/strong.ts +4 -3
- package/src/parser/inline/template.ts +16 -15
- package/src/parser/inline.test.ts +3 -3
- package/src/parser/segment.ts +3 -1
- package/src/parser/source/escapable.ts +9 -8
- package/src/parser/source/line.ts +4 -3
- package/src/parser/source/str.ts +2 -2
- package/src/parser/source/text.ts +19 -26
- package/src/parser/source/unescapable.ts +6 -5
- package/src/parser/util.ts +16 -30
- package/src/parser/visibility.ts +19 -20
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RubyParser } from '../inline';
|
|
2
2
|
import { Backtrack } from '../context';
|
|
3
|
-
import { eval } from '../../combinator/data/parser';
|
|
3
|
+
import { List, Data, eval } from '../../combinator/data/parser';
|
|
4
4
|
import { inits, surround, setBacktrack, dup, lazy, bind } from '../../combinator';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
6
|
import { txt } from '../source';
|
|
7
7
|
import { isTightNodeStart } from '../visibility';
|
|
8
|
-
import {
|
|
8
|
+
import { unwrap } from '../util';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const ruby: RubyParser = lazy(() => bind(
|
|
@@ -14,8 +14,8 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
14
14
|
'[', text, ']',
|
|
15
15
|
false,
|
|
16
16
|
([, ns]) => {
|
|
17
|
-
ns && ns.
|
|
18
|
-
return isTightNodeStart(ns) ?
|
|
17
|
+
ns && ns.last?.value === '' && ns.pop();
|
|
18
|
+
return isTightNodeStart(ns) ? ns : undefined;
|
|
19
19
|
},
|
|
20
20
|
undefined,
|
|
21
21
|
[1 | Backtrack.bracket, 3 | Backtrack.ruby])),
|
|
@@ -24,48 +24,49 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
24
24
|
false, undefined, undefined,
|
|
25
25
|
[1 | Backtrack.bracket, 3 | Backtrack.ruby])),
|
|
26
26
|
]),
|
|
27
|
-
([texts, rubies], context) => {
|
|
27
|
+
([{ value: texts }, { value: rubies = undefined } = {}], context) => {
|
|
28
28
|
if (rubies === undefined) {
|
|
29
29
|
const head = context.position - context.range!;
|
|
30
30
|
return void setBacktrack(context, [2 | Backtrack.ruby], head);
|
|
31
31
|
}
|
|
32
32
|
switch (true) {
|
|
33
|
-
case
|
|
34
|
-
return [
|
|
35
|
-
html('ruby', defrag(texts
|
|
36
|
-
.reduce((acc,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
, []))),
|
|
54
|
-
]];
|
|
33
|
+
case texts.length >= rubies.length:
|
|
34
|
+
return new List([
|
|
35
|
+
new Data(html('ruby', defrag(unwrap([...zip(texts, rubies)]
|
|
36
|
+
.reduce((acc, [{ value: text = '' } = {}, { value: ruby = '' } = {}]) =>
|
|
37
|
+
acc.import(
|
|
38
|
+
ruby
|
|
39
|
+
? new List([new Data(text), new Data(html('rp', '(')), new Data(html('rt', ruby)), new Data(html('rp', ')'))])
|
|
40
|
+
: new List([new Data(text), new Data(html('rt'))]))
|
|
41
|
+
, new List<Data<string | HTMLElement>>()))))),
|
|
42
|
+
]);
|
|
43
|
+
case texts.length === 1 && [...texts.head!.value].length >= rubies.length:
|
|
44
|
+
return new List([
|
|
45
|
+
new Data(html('ruby', defrag(unwrap([...zip(new List([...texts.head!.value].map(char => new Data(char))), rubies)]
|
|
46
|
+
.reduce((acc, [{ value: text = '' } = {}, { value: ruby = '' } = {}]) =>
|
|
47
|
+
acc.import(
|
|
48
|
+
ruby
|
|
49
|
+
? new List([new Data(text), new Data(html('rp', '(')), new Data(html('rt', ruby)), new Data(html('rp', ')'))])
|
|
50
|
+
: new List([new Data(text), new Data(html('rt'))]))
|
|
51
|
+
, new List<Data<string | HTMLElement>>()))))),
|
|
52
|
+
]);
|
|
55
53
|
default:
|
|
56
54
|
assert(rubies.length > 0);
|
|
57
|
-
return [
|
|
58
|
-
html('ruby', defrag(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
return new List([
|
|
56
|
+
new Data(html('ruby', defrag(unwrap(new List<Data<string | HTMLElement>>([
|
|
57
|
+
new Data(texts.foldr(({ value }, acc) => value + ' ' + acc, '').slice(0, -1)),
|
|
58
|
+
new Data(html('rp', '(')),
|
|
59
|
+
new Data(html('rt', rubies.foldr(({ value }, acc) => value + ' ' + acc, '').trim())),
|
|
60
|
+
new Data(html('rp', ')')),
|
|
61
|
+
]))))),
|
|
62
|
+
]);
|
|
62
63
|
}
|
|
63
64
|
}));
|
|
64
65
|
|
|
65
66
|
const text: RubyParser.TextParser = input => {
|
|
66
67
|
const { context } = input;
|
|
67
68
|
const { source } = context;
|
|
68
|
-
const acc = [''];
|
|
69
|
+
const acc = new List([new Data('')]);
|
|
69
70
|
let state = false;
|
|
70
71
|
context.sequential = true;
|
|
71
72
|
for (let { position } = context; position < source.length; position = context.position) {
|
|
@@ -75,41 +76,37 @@ const text: RubyParser.TextParser = input => {
|
|
|
75
76
|
case '&': {
|
|
76
77
|
const result = unsafehtmlentity(input) ?? txt(input)!;
|
|
77
78
|
assert(result);
|
|
78
|
-
acc
|
|
79
|
+
acc.last!.value += eval(result).head!.value;
|
|
79
80
|
continue;
|
|
80
81
|
}
|
|
81
82
|
default: {
|
|
82
83
|
if (source[position].trimStart() === '') {
|
|
83
|
-
state ||= acc.
|
|
84
|
-
acc.push('');
|
|
84
|
+
state ||= acc.last!.value.trimStart() !== '';
|
|
85
|
+
acc.push(new Data(''));
|
|
85
86
|
context.position += 1;
|
|
86
87
|
continue;
|
|
87
88
|
}
|
|
88
89
|
const result = txt(input)!;
|
|
89
90
|
assert(result);
|
|
90
|
-
acc
|
|
91
|
+
acc.last!.value += eval(result).head?.value ?? '';
|
|
91
92
|
continue;
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
context.sequential = false;
|
|
96
|
-
state ||= acc.
|
|
97
|
+
state ||= acc.last!.value.trimStart() !== '';
|
|
97
98
|
return state
|
|
98
|
-
?
|
|
99
|
+
? acc
|
|
99
100
|
: undefined;
|
|
100
101
|
};
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// }
|
|
113
|
-
// }
|
|
114
|
-
// return attrs ?? {};
|
|
115
|
-
//}
|
|
103
|
+
function* zip<N extends List.Node>(a: List<N>, b: List<N>): Iterable<[N | undefined, N | undefined]> {
|
|
104
|
+
const ia = a[Symbol.iterator]();
|
|
105
|
+
const ib = b[Symbol.iterator]();
|
|
106
|
+
while (true) {
|
|
107
|
+
const ra = ia.next();
|
|
108
|
+
const rb = ib.next();
|
|
109
|
+
if (ra.done) break;
|
|
110
|
+
yield [ra.value, rb.value];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { StrongParser } from '../inline';
|
|
2
2
|
import { Recursion } from '../context';
|
|
3
|
+
import { List, Data } from '../../combinator/data/parser';
|
|
3
4
|
import { union, some, recursion, precedence, surround, open, lazy } from '../../combinator';
|
|
4
5
|
import { inline } from '../inline';
|
|
5
6
|
import { emphasis } from './emphasis';
|
|
6
7
|
import { str } from '../source';
|
|
7
8
|
import { tightStart, blankWith } from '../visibility';
|
|
8
|
-
import {
|
|
9
|
+
import { unwrap } from '../util';
|
|
9
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
11
|
|
|
11
12
|
export const strong: StrongParser = lazy(() => surround(
|
|
@@ -17,5 +18,5 @@ export const strong: StrongParser = lazy(() => surround(
|
|
|
17
18
|
open(some(inline, '*'), inline),
|
|
18
19
|
]))))),
|
|
19
20
|
str('**'), false,
|
|
20
|
-
([, bs]) => [
|
|
21
|
-
([as, bs]) => bs &&
|
|
21
|
+
([, bs]) => new List([new Data(html('strong', defrag(unwrap(bs))))]),
|
|
22
|
+
([as, bs]) => bs && as.import(bs as List<Data<string>>)));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TemplateParser } from '../inline';
|
|
2
2
|
import { Recursion, Backtrack } from '../context';
|
|
3
|
+
import { List, Data } from '../../combinator/data/parser';
|
|
3
4
|
import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
|
|
4
5
|
import { escsource, str } from '../source';
|
|
5
|
-
import { invalid } from '../util';
|
|
6
|
-
import { unshift, push } from 'spica/array';
|
|
6
|
+
import { unwrap, invalid } from '../util';
|
|
7
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
9
|
export const template: TemplateParser = lazy(() => surround(
|
|
@@ -12,35 +12,36 @@ export const template: TemplateParser = lazy(() => surround(
|
|
|
12
12
|
some(union([bracket, escsource]), '}')),
|
|
13
13
|
str('}}'),
|
|
14
14
|
true,
|
|
15
|
-
([as, bs =
|
|
16
|
-
|
|
15
|
+
([as, bs = new List(), cs]) => new List([
|
|
16
|
+
new Data(html('span', { class: 'template' }, defrag(unwrap(as.import(bs as List<Data<string>>).import(cs)))))
|
|
17
|
+
]),
|
|
17
18
|
([, bs], context) =>
|
|
18
|
-
bs && [
|
|
19
|
-
html('span',
|
|
19
|
+
bs && new List([
|
|
20
|
+
new Data(html('span',
|
|
20
21
|
{
|
|
21
22
|
class: 'invalid',
|
|
22
23
|
...invalid('template', 'syntax', `Missing the closing symbol "}}"`),
|
|
23
24
|
},
|
|
24
|
-
context.source.slice(context.position - context.range!, context.position))
|
|
25
|
-
]
|
|
25
|
+
context.source.slice(context.position - context.range!, context.position)))
|
|
26
|
+
]),
|
|
26
27
|
[3 | Backtrack.doublebracket, 3 | Backtrack.escbracket]));
|
|
27
28
|
|
|
28
29
|
const bracket: TemplateParser.BracketParser = lazy(() => union([
|
|
29
30
|
surround(str('('), recursion(Recursion.terminal, some(union([bracket, escsource]), ')')), str(')'), true,
|
|
30
|
-
undefined, () =>
|
|
31
|
+
undefined, () => new List(), [3 | Backtrack.escbracket]),
|
|
31
32
|
surround(str('['), recursion(Recursion.terminal, some(union([bracket, escsource]), ']')), str(']'), true,
|
|
32
|
-
undefined, () =>
|
|
33
|
+
undefined, () => new List(), [3 | Backtrack.escbracket]),
|
|
33
34
|
surround(str('{'), recursion(Recursion.terminal, some(union([bracket, escsource]), '}')), str('}'), true,
|
|
34
|
-
undefined, () =>
|
|
35
|
+
undefined, () => new List(), [3 | Backtrack.escbracket]),
|
|
35
36
|
surround(
|
|
36
37
|
str('"'),
|
|
37
38
|
precedence(2, recursion(Recursion.terminal, some(escsource, /["\n]/y, [['"', 2], ['\n', 3]]))),
|
|
38
39
|
str('"'),
|
|
39
40
|
true,
|
|
40
|
-
([as, bs =
|
|
41
|
+
([as, bs = new List(), cs], context) =>
|
|
41
42
|
context.linebreak === 0
|
|
42
|
-
?
|
|
43
|
-
: (context.position -= 1,
|
|
44
|
-
([as, bs]) => bs &&
|
|
43
|
+
? as.import(bs as List<Data<string>>).import(cs)
|
|
44
|
+
: (context.position -= 1, as.import(bs as List<Data<string>>)),
|
|
45
|
+
([as, bs]) => bs && as.import(bs as List<Data<string>>),
|
|
45
46
|
[3 | Backtrack.escbracket]),
|
|
46
47
|
]));
|
|
@@ -56,9 +56,9 @@ describe('Unit: parser/inline', () => {
|
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('**a*b***'), ctx), [['<strong>a<em>b</em></strong>'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('**a*b***c'), ctx), [['<strong>a<em>b</em></strong>', 'c'], '']);
|
|
58
58
|
assert.deepStrictEqual(inspect(parser('**a**b****'), ctx), [['<strong>a</strong>', 'b', '****'], '']);
|
|
59
|
-
assert.deepStrictEqual(inspect(parser('**a**b****c'), ctx), [['<strong>a</strong>', 'b', '****
|
|
59
|
+
assert.deepStrictEqual(inspect(parser('**a**b****c'), ctx), [['<strong>a</strong>', 'b', '****c'], '']);
|
|
60
60
|
assert.deepStrictEqual(inspect(parser('**a***b*****'), ctx), [['<strong>a</strong>', '<em>b</em>', '****'], '']);
|
|
61
|
-
assert.deepStrictEqual(inspect(parser('**a***b*****c'), ctx), [['<strong>a</strong>', '<em>b</em>', '****
|
|
61
|
+
assert.deepStrictEqual(inspect(parser('**a***b*****c'), ctx), [['<strong>a</strong>', '<em>b</em>', '****c'], '']);
|
|
62
62
|
assert.deepStrictEqual(inspect(parser('**a *b***'), ctx), [['<strong>a <em>b</em></strong>'], '']);
|
|
63
63
|
assert.deepStrictEqual(inspect(parser('**a *b***c'), ctx), [['<strong>a <em>b</em></strong>', 'c'], '']);
|
|
64
64
|
assert.deepStrictEqual(inspect(parser('**a **b****'), ctx), [['<strong>a <strong>b</strong></strong>'], '']);
|
|
@@ -68,7 +68,7 @@ describe('Unit: parser/inline', () => {
|
|
|
68
68
|
assert.deepStrictEqual(inspect(parser('***a*'), ctx), [['**', '<em>a</em>'], '']);
|
|
69
69
|
assert.deepStrictEqual(inspect(parser('***a*b'), ctx), [['**', '<em>a</em>', 'b'], '']);
|
|
70
70
|
assert.deepStrictEqual(inspect(parser('***a*b*'), ctx), [['**', '<em>a</em>', 'b', '*'], '']);
|
|
71
|
-
assert.deepStrictEqual(inspect(parser('***a*b*c'), ctx), [['**', '<em>a</em>', 'b*c'], '']);
|
|
71
|
+
assert.deepStrictEqual(inspect(parser('***a*b*c'), ctx), [['**', '<em>a</em>', 'b', '*', 'c'], '']);
|
|
72
72
|
assert.deepStrictEqual(inspect(parser('***a*b*c*'), ctx), [['**', '<em>a</em>', 'b', '<em>c</em>'], '']);
|
|
73
73
|
assert.deepStrictEqual(inspect(parser('***a*b*c**'), ctx), [['**', '<em>a</em>', 'b', '<em>c</em>', '*'], '']);
|
|
74
74
|
assert.deepStrictEqual(inspect(parser('***a*b*c***'), ctx), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
|
package/src/parser/segment.ts
CHANGED
|
@@ -53,7 +53,9 @@ export function* segment(source: string): Generator<string, undefined, undefined
|
|
|
53
53
|
const result = parser(input)!;
|
|
54
54
|
assert(result);
|
|
55
55
|
assert(context.position > position);
|
|
56
|
-
const segs = eval(result).length
|
|
56
|
+
const segs = eval(result).length > 0
|
|
57
|
+
? eval(result).foldl<string[]>((acc, { value }) => void acc.push(value) || acc, [])
|
|
58
|
+
: [source.slice(position, context.position)];
|
|
57
59
|
assert(segs.join('') === source.slice(position, context.position));
|
|
58
60
|
for (let i = 0; i < segs.length; ++i) {
|
|
59
61
|
const seg = segs[i];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EscapableSourceParser } from '../source';
|
|
2
2
|
import { Command } from '../context';
|
|
3
|
+
import { List, Data } from '../../combinator/data/parser';
|
|
3
4
|
import { consume } from '../../combinator';
|
|
4
5
|
import { next } from './text';
|
|
5
6
|
import { html } from 'typed-dom/dom';
|
|
@@ -16,33 +17,33 @@ export const escsource: EscapableSourceParser = ({ context }) => {
|
|
|
16
17
|
case '\r':
|
|
17
18
|
assert(!source.includes('\r', position + 1));
|
|
18
19
|
consume(-1, context);
|
|
19
|
-
return
|
|
20
|
+
return new List();
|
|
20
21
|
case Command.Escape:
|
|
21
22
|
consume(1, context);
|
|
22
23
|
context.position += 1;
|
|
23
|
-
return [
|
|
24
|
+
return new List([new Data(source.slice(position + 1, position + 2))]);
|
|
24
25
|
case '\\':
|
|
25
26
|
switch (source[position + 1]) {
|
|
26
27
|
case undefined:
|
|
27
|
-
return [
|
|
28
|
+
return new List([new Data(char)]);
|
|
28
29
|
case '\n':
|
|
29
|
-
return [
|
|
30
|
+
return new List([new Data(char)]);
|
|
30
31
|
default:
|
|
31
32
|
consume(1, context);
|
|
32
33
|
context.position += 1;
|
|
33
|
-
return [
|
|
34
|
+
return new List([new Data(source.slice(position, position + 2))]);
|
|
34
35
|
}
|
|
35
36
|
case '\n':
|
|
36
37
|
context.linebreak ||= source.length - position;
|
|
37
|
-
return [
|
|
38
|
+
return new List([new Data(html('br'))]);
|
|
38
39
|
default:
|
|
39
40
|
assert(char !== '\n');
|
|
40
|
-
if (context.sequential) return [
|
|
41
|
+
if (context.sequential) return new List([new Data(char)]);
|
|
41
42
|
let i = next(source, position, delimiter);
|
|
42
43
|
assert(i > position);
|
|
43
44
|
i -= position;
|
|
44
45
|
consume(i - 1, context);
|
|
45
46
|
context.position += i - 1;
|
|
46
|
-
return [
|
|
47
|
+
return new List([new Data(source.slice(position, context.position))]);
|
|
47
48
|
}
|
|
48
49
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { AnyLineParser, EmptyLineParser, ContentLineParser } from '../source';
|
|
2
|
+
import { List } from '../../combinator/data/parser';
|
|
2
3
|
|
|
3
4
|
export const anyline: AnyLineParser = input => {
|
|
4
5
|
const { context } = input;
|
|
5
6
|
const { source, position } = context;
|
|
6
7
|
context.position = source.indexOf('\n', position) + 1 || source.length;
|
|
7
|
-
return
|
|
8
|
+
return new List();
|
|
8
9
|
};
|
|
9
10
|
const regEmptyline = /[^\S\n]*(?:$|\n)/y;
|
|
10
11
|
export const emptyline: EmptyLineParser = input => {
|
|
@@ -15,7 +16,7 @@ export const emptyline: EmptyLineParser = input => {
|
|
|
15
16
|
const i = regEmptyline.lastIndex;
|
|
16
17
|
if (i === 0) return;
|
|
17
18
|
context.position = i;
|
|
18
|
-
return
|
|
19
|
+
return new List();
|
|
19
20
|
};
|
|
20
21
|
const regContentline = /[^\S\n]*\S[^\n]*(?:$|\n)/y;
|
|
21
22
|
export const contentline: ContentLineParser = input => {
|
|
@@ -26,5 +27,5 @@ export const contentline: ContentLineParser = input => {
|
|
|
26
27
|
const i = regContentline.lastIndex;
|
|
27
28
|
if (i === 0) return;
|
|
28
29
|
context.position = i;
|
|
29
|
-
return
|
|
30
|
+
return new List();
|
|
30
31
|
}
|
package/src/parser/source/str.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StrParser } from '../source';
|
|
2
|
-
import { Parser } from '../../combinator/data/parser';
|
|
2
|
+
import { Parser, List, Data } from '../../combinator/data/parser';
|
|
3
3
|
import { matcher } from '../../combinator';
|
|
4
4
|
|
|
5
5
|
export function str(pattern: string | RegExp): StrParser;
|
|
@@ -17,6 +17,6 @@ export function strs(pattern: string): Parser<string> {
|
|
|
17
17
|
acc += pattern;
|
|
18
18
|
context.position += pattern.length;
|
|
19
19
|
}
|
|
20
|
-
return [
|
|
20
|
+
return new List([new Data(acc)]);
|
|
21
21
|
};
|
|
22
22
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TextParser, TxtParser, LinebreakParser } from '../source';
|
|
2
2
|
import { Command } from '../context';
|
|
3
|
+
import { List, Data } from '../../combinator/data/parser';
|
|
3
4
|
import { union, consume, focus } from '../../combinator';
|
|
4
5
|
import { html } from 'typed-dom/dom';
|
|
5
6
|
|
|
@@ -17,26 +18,26 @@ export const text: TextParser = input => {
|
|
|
17
18
|
case '\r':
|
|
18
19
|
assert(!source.includes('\r', position + 1));
|
|
19
20
|
consume(-1, context);
|
|
20
|
-
return
|
|
21
|
+
return new List();
|
|
21
22
|
case Command.Escape:
|
|
22
23
|
case '\\':
|
|
23
24
|
switch (source[position + 1]) {
|
|
24
25
|
case undefined:
|
|
25
|
-
return
|
|
26
|
+
return new List();
|
|
26
27
|
case '\n':
|
|
27
28
|
assert(char !== Command.Escape);
|
|
28
|
-
return
|
|
29
|
+
return new List();
|
|
29
30
|
default:
|
|
30
31
|
consume(1, context);
|
|
31
32
|
context.position += 1;
|
|
32
|
-
return [
|
|
33
|
+
return new List([new Data(source.slice(position + 1, context.position))]);
|
|
33
34
|
}
|
|
34
35
|
case '\n':
|
|
35
36
|
context.linebreak ||= source.length - position;
|
|
36
|
-
return [
|
|
37
|
+
return new List([new Data(html('br'))]);
|
|
37
38
|
default:
|
|
38
39
|
assert(char !== '\n');
|
|
39
|
-
if (context.sequential) return [
|
|
40
|
+
if (context.sequential) return new List([new Data(char)]);
|
|
40
41
|
nonWhitespace.lastIndex = position + 1;
|
|
41
42
|
const s = canSkip(source, position);
|
|
42
43
|
let i = s
|
|
@@ -54,8 +55,8 @@ export const text: TextParser = input => {
|
|
|
54
55
|
context.position += i - 1;
|
|
55
56
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
56
57
|
return position === context.position || s && !linestart || lineend
|
|
57
|
-
?
|
|
58
|
-
: [
|
|
58
|
+
? new List()
|
|
59
|
+
: new List([new Data(source.slice(position, context.position))]);
|
|
59
60
|
}
|
|
60
61
|
};
|
|
61
62
|
|
|
@@ -136,36 +137,30 @@ export function backToWhitespace(source: string, position: number, index: number
|
|
|
136
137
|
export function backToUrlHead(source: string, position: number, index: number): number {
|
|
137
138
|
const delim = index;
|
|
138
139
|
let state = false;
|
|
139
|
-
let
|
|
140
|
-
for (let i = index; --i > position;) {
|
|
141
|
-
index = i;
|
|
140
|
+
for (let i = index - 1; i >= position; --i) {
|
|
142
141
|
const char = source[i];
|
|
143
142
|
if (state) switch (char) {
|
|
144
143
|
case '.':
|
|
145
144
|
case '+':
|
|
146
145
|
case '-':
|
|
147
146
|
state = false;
|
|
148
|
-
offset = 1;
|
|
149
147
|
continue;
|
|
150
148
|
}
|
|
151
149
|
if (isAlphanumeric(char)) {
|
|
152
150
|
state = true;
|
|
153
|
-
|
|
151
|
+
index = i;
|
|
154
152
|
continue;
|
|
155
153
|
}
|
|
156
154
|
break;
|
|
157
155
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return index + offset;
|
|
156
|
+
return index === position
|
|
157
|
+
? delim
|
|
158
|
+
: index;
|
|
162
159
|
}
|
|
163
160
|
export function backToEmailHead(source: string, position: number, index: number): number {
|
|
164
161
|
const delim = index;
|
|
165
162
|
let state = false;
|
|
166
|
-
let
|
|
167
|
-
for (let i = index; --i > position;) {
|
|
168
|
-
index = i;
|
|
163
|
+
for (let i = index - 1; i >= position; --i) {
|
|
169
164
|
const char = source[i];
|
|
170
165
|
if (state) switch (char) {
|
|
171
166
|
case '_':
|
|
@@ -173,20 +168,18 @@ export function backToEmailHead(source: string, position: number, index: number)
|
|
|
173
168
|
case '+':
|
|
174
169
|
case '-':
|
|
175
170
|
state = false;
|
|
176
|
-
offset = 1;
|
|
177
171
|
continue;
|
|
178
172
|
}
|
|
179
173
|
if (isAlphanumeric(char)) {
|
|
180
174
|
state = true;
|
|
181
|
-
|
|
175
|
+
index = i;
|
|
182
176
|
continue;
|
|
183
177
|
}
|
|
184
178
|
break;
|
|
185
179
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return index + offset;
|
|
180
|
+
return index === position
|
|
181
|
+
? delim
|
|
182
|
+
: index;
|
|
190
183
|
}
|
|
191
184
|
function isAlphanumeric(char: string): boolean {
|
|
192
185
|
assert(char.length === 1);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UnescapableSourceParser } from '../source';
|
|
2
2
|
import { Command } from '../context';
|
|
3
|
+
import { List, Data } from '../../combinator/data/parser';
|
|
3
4
|
import { consume } from '../../combinator';
|
|
4
5
|
import { nonWhitespace, canSkip, next } from './text';
|
|
5
6
|
import { html } from 'typed-dom/dom';
|
|
@@ -16,17 +17,17 @@ export const unescsource: UnescapableSourceParser = ({ context }) => {
|
|
|
16
17
|
case '\r':
|
|
17
18
|
assert(!source.includes('\r', position + 1));
|
|
18
19
|
consume(-1, context);
|
|
19
|
-
return
|
|
20
|
+
return new List();
|
|
20
21
|
case Command.Escape:
|
|
21
22
|
consume(1, context);
|
|
22
23
|
context.position += 1;
|
|
23
|
-
return [
|
|
24
|
+
return new List([new Data(source.slice(position + 1, position + 2))]);
|
|
24
25
|
case '\n':
|
|
25
26
|
context.linebreak ||= source.length - position;
|
|
26
|
-
return [
|
|
27
|
+
return new List([new Data(html('br'))]);
|
|
27
28
|
default:
|
|
28
29
|
assert(char !== '\n');
|
|
29
|
-
if (context.sequential) return [
|
|
30
|
+
if (context.sequential) return new List([new Data(char)]);
|
|
30
31
|
nonWhitespace.lastIndex = position + 1;
|
|
31
32
|
let i = canSkip(source, position)
|
|
32
33
|
? nonWhitespace.test(source)
|
|
@@ -37,6 +38,6 @@ export const unescsource: UnescapableSourceParser = ({ context }) => {
|
|
|
37
38
|
i -= position;
|
|
38
39
|
consume(i - 1, context);
|
|
39
40
|
context.position += i - 1;
|
|
40
|
-
return [
|
|
41
|
+
return new List([new Data(source.slice(position, context.position))]);
|
|
41
42
|
}
|
|
42
43
|
};
|
package/src/parser/util.ts
CHANGED
|
@@ -1,47 +1,34 @@
|
|
|
1
1
|
import { min } from 'spica/alias';
|
|
2
2
|
import { MarkdownParser } from '../../markdown';
|
|
3
3
|
import { Command } from './context';
|
|
4
|
-
import { Parser, Result, Ctx, Node, Context, eval, failsafe } from '../combinator/data/parser';
|
|
5
|
-
import { convert } from '../combinator';
|
|
4
|
+
import { Parser, Result, List, Data, Ctx, Node, Context, eval, failsafe } from '../combinator/data/parser';
|
|
6
5
|
import { define } from 'typed-dom/dom';
|
|
7
6
|
|
|
8
|
-
export function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
trim === 0
|
|
13
|
-
? source
|
|
14
|
-
: trim > 0
|
|
15
|
-
? source.at(-1) === '\n'
|
|
16
|
-
? source
|
|
17
|
-
: source + '\n'
|
|
18
|
-
: source.at(-1) === '\n'
|
|
19
|
-
? source.slice(0, -1)
|
|
20
|
-
: source
|
|
21
|
-
}`,
|
|
22
|
-
parser,
|
|
23
|
-
trim === 0);
|
|
7
|
+
export function* unwrap<N>(nodes: List<Data<N>>): Iterable<N> {
|
|
8
|
+
for (const node of nodes) {
|
|
9
|
+
yield node.value;
|
|
10
|
+
}
|
|
24
11
|
}
|
|
25
12
|
|
|
26
|
-
export function repeat<P extends Parser<HTMLElement |
|
|
27
|
-
export function repeat<N extends HTMLElement |
|
|
28
|
-
const acc =
|
|
13
|
+
export function repeat<P extends Parser<HTMLElement | string, MarkdownParser.Context>>(symbol: string, parser: P, cons: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<Node<P>>>, termination?: (acc: List<Data<Node<P>>>, context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | Node<P>>): P;
|
|
14
|
+
export function repeat<N extends HTMLElement | string>(symbol: string, parser: Parser<N>, cons: (nodes: List<Data<N>>, context: MarkdownParser.Context) => List<Data<N>>, termination: (acc: List<Data<N>>, context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | N, MarkdownParser.Context> = (nodes, context, prefix, postfix) => {
|
|
15
|
+
const acc = new List<Data<string | N>>();
|
|
29
16
|
if (prefix > 0) {
|
|
30
|
-
acc.push(symbol[0].repeat(prefix));
|
|
17
|
+
acc.push(new Data(symbol[0].repeat(prefix)));
|
|
31
18
|
}
|
|
32
|
-
acc.
|
|
19
|
+
acc.import(nodes);
|
|
33
20
|
if (postfix > 0) {
|
|
34
21
|
const { source, position } = context;
|
|
35
|
-
acc.push(source.slice(position, position + postfix));
|
|
22
|
+
acc.push(new Data(source.slice(position, position + postfix)));
|
|
36
23
|
context.position += postfix;
|
|
37
24
|
}
|
|
38
|
-
return
|
|
25
|
+
return acc;
|
|
39
26
|
}): Parser<string | N, MarkdownParser.Context> {
|
|
40
27
|
return failsafe(input => {
|
|
41
28
|
const { context } = input;
|
|
42
29
|
const { source, position } = context;
|
|
43
30
|
assert(source.startsWith(symbol, context.position));
|
|
44
|
-
let nodes
|
|
31
|
+
let nodes = new List<Data<N>>();
|
|
45
32
|
let i = symbol.length;
|
|
46
33
|
while (source[context.position + i] === source[context.position]) ++i;
|
|
47
34
|
context.position += i;
|
|
@@ -58,7 +45,7 @@ export function repeat<N extends HTMLElement | string>(symbol: string, parser:
|
|
|
58
45
|
context.buffer = buf;
|
|
59
46
|
if (result === undefined) break;
|
|
60
47
|
nodes = eval(result);
|
|
61
|
-
switch (nodes.
|
|
48
|
+
switch (nodes.last?.value) {
|
|
62
49
|
case Command.Cancel:
|
|
63
50
|
assert(!source.startsWith(symbol, context.position));
|
|
64
51
|
nodes.pop();
|
|
@@ -124,10 +111,9 @@ export function unmarkInvalid<N extends HTMLElement>(el: N): N {
|
|
|
124
111
|
});
|
|
125
112
|
}
|
|
126
113
|
|
|
127
|
-
export function stringify(nodes:
|
|
114
|
+
export function stringify(nodes: Iterable<HTMLElement | string>): string {
|
|
128
115
|
let acc = '';
|
|
129
|
-
for (
|
|
130
|
-
const node = nodes[i];
|
|
116
|
+
for (const node of nodes) {
|
|
131
117
|
if (typeof node === 'string') {
|
|
132
118
|
assert(!node.includes('\n'));
|
|
133
119
|
acc += node;
|