securemark 0.299.1 → 0.299.3
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 +192 -138
- package/markdown.d.ts +2 -2
- package/package.json +1 -1
- package/src/combinator/control/manipulation/fence.ts +2 -2
- package/src/combinator/control/manipulation/match.ts +2 -2
- package/src/combinator/data/delimiter.ts +5 -3
- package/src/combinator/data/parser/context.ts +12 -38
- package/src/combinator/data/parser/some.ts +13 -6
- package/src/parser/api/header.ts +5 -1
- package/src/parser/api/parse.test.ts +9 -9
- package/src/parser/block/blockquote.ts +2 -2
- package/src/parser/block.ts +1 -1
- package/src/parser/context.ts +5 -6
- package/src/parser/header.test.ts +5 -5
- package/src/parser/header.ts +2 -3
- package/src/parser/inline/annotation.ts +9 -4
- package/src/parser/inline/autolink/url.ts +3 -4
- package/src/parser/inline/deletion.ts +1 -1
- package/src/parser/inline/emstrong.ts +1 -1
- package/src/parser/inline/insertion.ts +1 -1
- package/src/parser/inline/italic.ts +1 -1
- package/src/parser/inline/link.ts +2 -2
- package/src/parser/inline/mark.ts +1 -1
- package/src/parser/inline/math.test.ts +2 -2
- package/src/parser/inline/math.ts +3 -3
- package/src/parser/inline/media.ts +2 -2
- package/src/parser/inline/ruby.ts +2 -3
- package/src/parser/inline.test.ts +1 -1
- package/src/parser/inline.ts +1 -1
- package/src/parser/repeat.ts +11 -23
- package/src/parser/source/escapable.ts +33 -10
- package/src/parser/source/text.ts +15 -24
- package/src/parser/source/unescapable.test.ts +1 -1
- package/src/parser/source/unescapable.ts +90 -9
|
@@ -2,7 +2,7 @@ import { MediaParser } from '../inline';
|
|
|
2
2
|
import { State, Recursion, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
4
|
import { Flag } from '../node';
|
|
5
|
-
import { union, inits, tails, some,
|
|
5
|
+
import { union, inits, tails, some, spend, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
6
6
|
import { uri, option as linkoption, resolve, decode, parse } from './link';
|
|
7
7
|
import { attributes } from './html';
|
|
8
8
|
import { unsafehtmlentity } from './htmlentity';
|
|
@@ -59,7 +59,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, open(
|
|
|
59
59
|
text = text.trim();
|
|
60
60
|
if (text === '' || text[0] !== tmp[0]) return;
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
spend(context, 100);
|
|
63
63
|
if (params.last!.value === Command.Cancel) {
|
|
64
64
|
params.pop();
|
|
65
65
|
return new List([
|
|
@@ -20,13 +20,12 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
20
20
|
})),
|
|
21
21
|
dup(surround(
|
|
22
22
|
'(', text, ')',
|
|
23
|
-
false,
|
|
24
|
-
[3 | Backtrack.ruby])),
|
|
23
|
+
false)),
|
|
25
24
|
]),
|
|
26
25
|
([{ value: texts }, { value: rubies = undefined } = {}], context) => {
|
|
27
26
|
if (rubies === undefined) {
|
|
28
27
|
const head = context.position - context.range;
|
|
29
|
-
return void setBacktrack(context, 2 | Backtrack.ruby, head);
|
|
28
|
+
return void setBacktrack(context, 2 | Backtrack.link | Backtrack.ruby, head);
|
|
30
29
|
}
|
|
31
30
|
switch (true) {
|
|
32
31
|
case texts.length >= rubies.length:
|
|
@@ -167,7 +167,7 @@ describe('Unit: parser/inline', () => {
|
|
|
167
167
|
assert.deepStrictEqual(inspect(parser, input('"[% "*"* %]', new Context())), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
|
|
168
168
|
assert.deepStrictEqual(inspect(parser, input('"{{""}}', new Context())), [['"', '{', '<a class="url" href="""">""</a>', '}'], '']);
|
|
169
169
|
assert.deepStrictEqual(inspect(parser, input('[#http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::http://host/(<bdi>)">http://host/<span class="paren">(<span class="invalid"><bdi></span>)</span></a>', '</bdi', '>'], '']);
|
|
170
|
-
assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host
|
|
170
|
+
assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host/(<bdi>)</a>', '</bdi', '>'], '']);
|
|
171
171
|
assert.deepStrictEqual(inspect(parser, input('[#a|<bdi>]</bdi>', new Context())), [['<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
172
172
|
assert.deepStrictEqual(inspect(parser, input('[[#a|<bdi>]</bdi>', new Context())), [['[', '<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
173
173
|
assert.deepStrictEqual(inspect(parser, input('[*==*]{a}', new Context())), [['<a class="link" href="a">*==*</a>'], '']);
|
package/src/parser/inline.ts
CHANGED
package/src/parser/repeat.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Parser, Result, List, Node } from '../combinator/data/parser';
|
|
2
2
|
import { tester } from '../combinator/data/delimiter';
|
|
3
|
+
import { recur } from '../combinator';
|
|
3
4
|
import { Context, Recursion, Command } from './context';
|
|
4
5
|
import { min } from 'spica/alias';
|
|
5
6
|
|
|
6
7
|
export function repeat<P extends Parser<HTMLElement | string, Context>>(
|
|
7
|
-
opener: string, after: string | RegExp, closer: string,
|
|
8
|
+
opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: P,
|
|
8
9
|
cons: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>, lead: number, follow: number) =>
|
|
9
10
|
List<Node<Parser.Node<P>>>,
|
|
10
11
|
termination?: (acc: List<Node<Parser.Node<P>>>, context: Context, prefix: number, postfix: number, state: boolean) =>
|
|
11
12
|
Result<string | Parser.Node<P>>,
|
|
12
13
|
): P;
|
|
13
14
|
export function repeat<N extends HTMLElement | string>(
|
|
14
|
-
opener: string, after: string | RegExp, closer: string,
|
|
15
|
+
opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: Parser<N>,
|
|
15
16
|
cons: (nodes: List<Node<N>>, context: Context, lead: number, follow: number) =>
|
|
16
17
|
List<Node<N>>,
|
|
17
18
|
termination: (acc: List<Node<N>>, context: Context, prefix: number, postfix: number, state: boolean) =>
|
|
@@ -35,7 +36,7 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
35
36
|
const test = tester(after, false);
|
|
36
37
|
return input => {
|
|
37
38
|
const context = input;
|
|
38
|
-
const { source, position, resources: { recursions }
|
|
39
|
+
const { source, position, resources: { recursions } } = context;
|
|
39
40
|
if (!source.startsWith(opener, context.position)) return;
|
|
40
41
|
let nodes = new List<Node<N>>();
|
|
41
42
|
let i = opener.length;
|
|
@@ -46,20 +47,11 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
let depth = i / opener.length + 1 | 0;
|
|
49
|
-
|
|
50
|
-
const rec = min(recursion, recursions.length - 1);
|
|
51
|
-
if (rec === -1) continue;
|
|
52
|
-
if (recursions[rec] < depth - 1) throw new Error('Too much recursion');
|
|
53
|
-
recursions[rec] -= depth;
|
|
54
|
-
}
|
|
50
|
+
recur(recursions, recursion, depth, true);
|
|
55
51
|
let state = false;
|
|
56
52
|
let follow = 0;
|
|
57
53
|
for (; i >= opener.length; i -= opener.length, follow -= closer.length) {
|
|
58
|
-
|
|
59
|
-
const rec = min(recursion, recursions.length - 1);
|
|
60
|
-
if (rec === -1) continue;
|
|
61
|
-
recursions[rec] += 1;
|
|
62
|
-
}
|
|
54
|
+
recur(recursions, recursion, -1);
|
|
63
55
|
depth -= 1;
|
|
64
56
|
const lead = i - opener.length;
|
|
65
57
|
if (source.startsWith(closer, context.position)) {
|
|
@@ -68,10 +60,10 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
68
60
|
follow = follow > 0 ? follow : countFollows(source, pos, closer, lead / opener.length | 0);
|
|
69
61
|
nodes = cons(nodes, context, lead, follow);
|
|
70
62
|
if (context.position > pos) {
|
|
71
|
-
const advance =
|
|
63
|
+
const advance = context.position - pos;
|
|
72
64
|
i -= advance;
|
|
73
65
|
follow -= advance;
|
|
74
|
-
depth -= advance;
|
|
66
|
+
depth -= advance / closer.length | 0;
|
|
75
67
|
}
|
|
76
68
|
continue;
|
|
77
69
|
}
|
|
@@ -100,20 +92,16 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
100
92
|
nodes = cons(nodes, context, lead, follow);
|
|
101
93
|
state = true;
|
|
102
94
|
if (context.position > pos) {
|
|
103
|
-
const advance =
|
|
95
|
+
const advance = context.position - pos;
|
|
104
96
|
i -= advance;
|
|
105
97
|
follow -= advance;
|
|
106
|
-
depth -= advance;
|
|
98
|
+
depth -= advance / closer.length | 0;
|
|
107
99
|
}
|
|
108
100
|
continue;
|
|
109
101
|
}
|
|
110
102
|
break;
|
|
111
103
|
}
|
|
112
|
-
|
|
113
|
-
const rec = min(recursion, recursions.length - 1);
|
|
114
|
-
if (rec === -1) continue;
|
|
115
|
-
recursions[rec] += depth;
|
|
116
|
-
}
|
|
104
|
+
recur(recursions, recursion, -depth);
|
|
117
105
|
depth = 0;
|
|
118
106
|
const prefix = i;
|
|
119
107
|
i = 0;
|
|
@@ -2,21 +2,18 @@ import { EscapableSourceParser } from '../source';
|
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import {
|
|
6
|
-
import { next } from './text';
|
|
5
|
+
import { spend } from '../../combinator';
|
|
7
6
|
import { html } from 'typed-dom/dom';
|
|
8
7
|
|
|
9
|
-
const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
|
|
10
|
-
|
|
11
8
|
export const escsource: EscapableSourceParser = context => {
|
|
12
|
-
const { source, position
|
|
9
|
+
const { source, position } = context;
|
|
13
10
|
if (position === source.length) return;
|
|
14
11
|
const char = source[position];
|
|
15
|
-
|
|
12
|
+
spend(context, 1);
|
|
16
13
|
context.position += 1;
|
|
17
14
|
switch (char) {
|
|
18
15
|
case Command.Escape:
|
|
19
|
-
|
|
16
|
+
spend(context, 1);
|
|
20
17
|
context.position += 1;
|
|
21
18
|
return new List([new Node(source.slice(position + 1, position + 2))]);
|
|
22
19
|
case '\\':
|
|
@@ -26,7 +23,7 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
26
23
|
case '\n':
|
|
27
24
|
return new List([new Node(char)]);
|
|
28
25
|
default:
|
|
29
|
-
|
|
26
|
+
spend(context, 1);
|
|
30
27
|
context.position += 1;
|
|
31
28
|
return new List([new Node(source.slice(position, position + 2))]);
|
|
32
29
|
}
|
|
@@ -38,11 +35,37 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
38
35
|
default:
|
|
39
36
|
assert(char !== '\n');
|
|
40
37
|
if (context.sequential) return new List([new Node(char)]);
|
|
41
|
-
let i =
|
|
38
|
+
let i = seek(source, position);
|
|
42
39
|
assert(i > position);
|
|
43
40
|
i -= position;
|
|
44
|
-
|
|
41
|
+
spend(context, i - 1);
|
|
45
42
|
context.position += i - 1;
|
|
46
43
|
return new List([new Node(source.slice(position, context.position))]);
|
|
47
44
|
}
|
|
48
45
|
};
|
|
46
|
+
|
|
47
|
+
function seek(source: string, position: number): number {
|
|
48
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
49
|
+
const char = source[i];
|
|
50
|
+
switch (char) {
|
|
51
|
+
case '\\':
|
|
52
|
+
case '$':
|
|
53
|
+
case '"':
|
|
54
|
+
case '`':
|
|
55
|
+
case ':':
|
|
56
|
+
case '[':
|
|
57
|
+
case ']':
|
|
58
|
+
case '(':
|
|
59
|
+
case ')':
|
|
60
|
+
case '{':
|
|
61
|
+
case '}':
|
|
62
|
+
case '\r':
|
|
63
|
+
case '\n':
|
|
64
|
+
return i;
|
|
65
|
+
default:
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
assert(false);
|
|
69
|
+
}
|
|
70
|
+
return source.length;
|
|
71
|
+
}
|
|
@@ -2,7 +2,7 @@ import { TextParser, TxtParser } from '../source';
|
|
|
2
2
|
import { State, Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import { union,
|
|
5
|
+
import { union, spend } from '../../combinator';
|
|
6
6
|
import { html } from 'typed-dom/dom';
|
|
7
7
|
|
|
8
8
|
export const nonWhitespace = /[^ \t ]/g;
|
|
@@ -12,7 +12,7 @@ export const text: TextParser = input => {
|
|
|
12
12
|
const { source, position, state } = context;
|
|
13
13
|
if (position === source.length) return;
|
|
14
14
|
const char = source[position];
|
|
15
|
-
|
|
15
|
+
spend(context, 1);
|
|
16
16
|
context.position += 1;
|
|
17
17
|
switch (char) {
|
|
18
18
|
case Command.Escape:
|
|
@@ -25,7 +25,7 @@ export const text: TextParser = input => {
|
|
|
25
25
|
assert(char !== Command.Escape);
|
|
26
26
|
return new List();
|
|
27
27
|
default:
|
|
28
|
-
|
|
28
|
+
spend(context, 1);
|
|
29
29
|
context.position += 1;
|
|
30
30
|
return new List([new Node(source.slice(position + 1, context.position))]);
|
|
31
31
|
}
|
|
@@ -51,7 +51,7 @@ export const text: TextParser = input => {
|
|
|
51
51
|
|| s && source[i] === '\n';
|
|
52
52
|
i -= position;
|
|
53
53
|
i = lineend ? i : i - +s || 1;
|
|
54
|
-
|
|
54
|
+
spend(context, i - 1);
|
|
55
55
|
context.position += i - 1;
|
|
56
56
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
57
57
|
if (position === context.position || s && !linestart || lineend) return new List();
|
|
@@ -83,28 +83,20 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
let index
|
|
88
|
-
if (delimiter) {
|
|
89
|
-
delimiter.lastIndex = position + 1;
|
|
90
|
-
delimiter.test(source);
|
|
91
|
-
index = delimiter.lastIndex || position;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
index = seek(source, position, state);
|
|
95
|
-
}
|
|
96
|
-
if (index === position || index === source.length) return source.length;
|
|
86
|
+
function next(source: string, position: number, state: number): number {
|
|
87
|
+
let index= seek(source, position, state);
|
|
97
88
|
assert(index > position);
|
|
89
|
+
if (index === source.length) return index;
|
|
98
90
|
const char = source[index];
|
|
99
91
|
switch (char) {
|
|
100
92
|
case '%':
|
|
101
|
-
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true)
|
|
102
|
-
index +=
|
|
93
|
+
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true));
|
|
94
|
+
index += index - 1 > position
|
|
103
95
|
? -1
|
|
104
96
|
: 0;
|
|
105
97
|
break;
|
|
106
98
|
case '[':
|
|
107
|
-
index +=
|
|
99
|
+
index += index - 1 > position && source.startsWith(' [|', index - 1)
|
|
108
100
|
? -1
|
|
109
101
|
: 0;
|
|
110
102
|
break;
|
|
@@ -122,7 +114,7 @@ export function next(source: string, position: number, state: number, delimiter?
|
|
|
122
114
|
assert(index > position);
|
|
123
115
|
return index;
|
|
124
116
|
}
|
|
125
|
-
function backToUrlHead(source: string, position: number, index: number): number {
|
|
117
|
+
export function backToUrlHead(source: string, position: number, index: number): number {
|
|
126
118
|
const delim = index;
|
|
127
119
|
let state = false;
|
|
128
120
|
for (let i = index - 1; i >= position; --i) {
|
|
@@ -145,7 +137,7 @@ function backToUrlHead(source: string, position: number, index: number): number
|
|
|
145
137
|
? delim
|
|
146
138
|
: index;
|
|
147
139
|
}
|
|
148
|
-
function backToEmailHead(source: string, position: number, index: number): number {
|
|
140
|
+
export function backToEmailHead(source: string, position: number, index: number): number {
|
|
149
141
|
const delim = index;
|
|
150
142
|
let state = false;
|
|
151
143
|
for (let i = index - 1; i >= position; --i) {
|
|
@@ -171,10 +163,9 @@ function backToEmailHead(source: string, position: number, index: number): numbe
|
|
|
171
163
|
}
|
|
172
164
|
export function isAlphanumeric(char: string): boolean {
|
|
173
165
|
assert(char.length === 1);
|
|
174
|
-
if (char < '0' || '
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|| 'a' <= char && char <= 'z';
|
|
166
|
+
if (char < '0' || 'z' < char) return false;
|
|
167
|
+
if (char <= '9' || 'a' <= char) return true;
|
|
168
|
+
return 'A' <= char && char <= 'Z';
|
|
178
169
|
}
|
|
179
170
|
|
|
180
171
|
function seek(source: string, position: number, state: number): number {
|
|
@@ -15,7 +15,7 @@ describe('Unit: parser/source/unescapable', () => {
|
|
|
15
15
|
it('basic', () => {
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('a', new Context())), [['a'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser, input('ab', new Context())), [['ab'], '']);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b
|
|
18
|
+
assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b c'], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser, input('09あいAZaz', new Context())), [['09', 'あいAZaz'], '']);
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { UnescapableSourceParser } from '../source';
|
|
2
|
-
import { Command } from '../context';
|
|
2
|
+
import { State, Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import {
|
|
6
|
-
import { nonWhitespace, canSkip,
|
|
5
|
+
import { spend } from '../../combinator';
|
|
6
|
+
import { nonWhitespace, canSkip, backToUrlHead, backToEmailHead } from './text';
|
|
7
7
|
import { html } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
|
-
export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
|
|
10
|
-
|
|
11
9
|
export const unescsource: UnescapableSourceParser = context => {
|
|
12
10
|
const { source, position, state } = context;
|
|
13
11
|
if (position === source.length) return;
|
|
14
12
|
const char = source[position];
|
|
15
|
-
|
|
13
|
+
spend(context, 1);
|
|
16
14
|
context.position += 1;
|
|
17
15
|
switch (char) {
|
|
18
16
|
case Command.Escape:
|
|
19
|
-
|
|
17
|
+
spend(context, 1);
|
|
20
18
|
context.position += 1;
|
|
21
19
|
return new List([new Node(source.slice(position + 1, position + 2))]);
|
|
22
20
|
case '\r':
|
|
@@ -32,11 +30,94 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
32
30
|
? nonWhitespace.test(source)
|
|
33
31
|
? nonWhitespace.lastIndex - 1
|
|
34
32
|
: source.length
|
|
35
|
-
: next(source, position, state
|
|
33
|
+
: next(source, position, state);
|
|
36
34
|
assert(i > position);
|
|
37
35
|
i -= position;
|
|
38
|
-
|
|
36
|
+
spend(context, i - 1);
|
|
39
37
|
context.position += i - 1;
|
|
40
38
|
return new List([new Node(source.slice(position, context.position))]);
|
|
41
39
|
}
|
|
42
40
|
};
|
|
41
|
+
|
|
42
|
+
function next(source: string, position: number, state: number): number {
|
|
43
|
+
let index= seek(source, position, state);
|
|
44
|
+
assert(index > position);
|
|
45
|
+
if (index === source.length) return index;
|
|
46
|
+
const char = source[index];
|
|
47
|
+
switch (char) {
|
|
48
|
+
case ':':
|
|
49
|
+
index = source.startsWith('//', index + 1)
|
|
50
|
+
? backToUrlHead(source, position, index)
|
|
51
|
+
: index;
|
|
52
|
+
break;
|
|
53
|
+
case '@':
|
|
54
|
+
index = ~state & State.autolink
|
|
55
|
+
? backToEmailHead(source, position, index)
|
|
56
|
+
: index;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
assert(index > position);
|
|
60
|
+
return index;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function seek(source: string, position: number, state: number): number {
|
|
64
|
+
const cat = category(source[position]);
|
|
65
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
66
|
+
const char = source[i];
|
|
67
|
+
switch (char) {
|
|
68
|
+
case '\\':
|
|
69
|
+
case '!':
|
|
70
|
+
case '$':
|
|
71
|
+
case '"':
|
|
72
|
+
case '`':
|
|
73
|
+
case '[':
|
|
74
|
+
case ']':
|
|
75
|
+
case '(':
|
|
76
|
+
case ')':
|
|
77
|
+
case '{':
|
|
78
|
+
case '}':
|
|
79
|
+
case '<':
|
|
80
|
+
case '>':
|
|
81
|
+
case '(':
|
|
82
|
+
case ')':
|
|
83
|
+
case '[':
|
|
84
|
+
case ']':
|
|
85
|
+
case '{':
|
|
86
|
+
case '}':
|
|
87
|
+
case '-':
|
|
88
|
+
case '+':
|
|
89
|
+
case '*':
|
|
90
|
+
case '=':
|
|
91
|
+
case '~':
|
|
92
|
+
case '^':
|
|
93
|
+
case '_':
|
|
94
|
+
case ',':
|
|
95
|
+
case '.':
|
|
96
|
+
case ';':
|
|
97
|
+
case ':':
|
|
98
|
+
case '!':
|
|
99
|
+
case '?':
|
|
100
|
+
case '/':
|
|
101
|
+
case '|':
|
|
102
|
+
case '\r':
|
|
103
|
+
case '\n':
|
|
104
|
+
return i;
|
|
105
|
+
case '@':
|
|
106
|
+
case '#':
|
|
107
|
+
if (~state & State.autolink) return i;
|
|
108
|
+
continue;
|
|
109
|
+
case ':':
|
|
110
|
+
if (source[i + 1] === '/' && source[i + 2] === '/') return i;
|
|
111
|
+
continue;
|
|
112
|
+
default:
|
|
113
|
+
if (cat && !category(char)) return i;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
assert(false);
|
|
117
|
+
}
|
|
118
|
+
return source.length;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function category(char: string): boolean {
|
|
122
|
+
return char <= '\x7E' && '\x21' <= char;
|
|
123
|
+
}
|