securemark 0.293.0 → 0.293.2
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 +254 -193
- package/markdown.d.ts +13 -21
- package/package.json +1 -1
- package/src/combinator/control/manipulation/scope.ts +3 -4
- package/src/combinator/data/parser/context.ts +5 -5
- package/src/combinator.ts +0 -1
- package/src/parser/api/parse.test.ts +2 -2
- package/src/parser/autolink.test.ts +7 -7
- package/src/parser/block/blockquote.ts +2 -2
- package/src/parser/block/codeblock.ts +7 -7
- package/src/parser/block/dlist.ts +1 -2
- package/src/parser/block/extension/aside.ts +3 -3
- package/src/parser/block/extension/example.ts +3 -3
- package/src/parser/block/extension/fig.ts +2 -2
- package/src/parser/block/extension/figure.test.ts +1 -1
- package/src/parser/block/extension/figure.ts +2 -2
- package/src/parser/block/extension/message.ts +3 -3
- package/src/parser/block/extension/placeholder.ts +7 -7
- package/src/parser/block/extension/table.ts +26 -16
- package/src/parser/block/extension.ts +3 -3
- package/src/parser/block/ilist.ts +3 -3
- package/src/parser/block/mathblock.ts +7 -7
- package/src/parser/block/mediablock.ts +6 -6
- package/src/parser/block/olist.ts +3 -3
- package/src/parser/block/paragraph.test.ts +1 -2
- package/src/parser/block/paragraph.ts +1 -2
- package/src/parser/block/reply/cite.ts +3 -5
- package/src/parser/block/reply/quote.ts +2 -3
- package/src/parser/block/sidefence.ts +2 -2
- package/src/parser/block/table.ts +5 -5
- package/src/parser/block/ulist.ts +2 -3
- package/src/parser/block.ts +2 -2
- package/src/parser/context.ts +4 -4
- package/src/parser/inline/annotation.ts +1 -1
- package/src/parser/inline/autolink/url.test.ts +7 -7
- package/src/parser/inline/autolink/url.ts +1 -2
- package/src/parser/inline/autolink.ts +1 -1
- package/src/parser/inline/bracket.test.ts +2 -2
- package/src/parser/inline/extension/index.ts +5 -4
- package/src/parser/inline/extension/indexer.test.ts +0 -1
- package/src/parser/inline/extension/indexer.ts +1 -1
- package/src/parser/inline/html.ts +7 -6
- package/src/parser/inline/htmlentity.ts +3 -3
- package/src/parser/inline/italic.test.ts +11 -11
- package/src/parser/inline/link.ts +1 -6
- package/src/parser/inline/mark.test.ts +5 -5
- package/src/parser/inline/math.ts +3 -3
- package/src/parser/inline/media.ts +3 -8
- package/src/parser/inline/reference.ts +1 -1
- package/src/parser/inline/remark.test.ts +14 -18
- package/src/parser/inline/remark.ts +17 -19
- package/src/parser/inline/ruby.ts +3 -3
- package/src/parser/inline/shortmedia.ts +1 -1
- package/src/parser/inline.test.ts +25 -24
- package/src/parser/inline.ts +21 -9
- package/src/parser/segment.ts +23 -5
- package/src/parser/source/escapable.test.ts +1 -1
- package/src/parser/source/escapable.ts +4 -12
- package/src/parser/source/text.test.ts +40 -40
- package/src/parser/source/text.ts +77 -24
- package/src/parser/source/unescapable.test.ts +3 -3
- package/src/parser/source/unescapable.ts +4 -12
- package/src/parser/visibility.ts +32 -32
- package/src/combinator/control/manipulation/trim.test.ts +0 -23
- package/src/combinator/control/manipulation/trim.ts +0 -17
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import { RemarkParser } from '../inline';
|
|
2
2
|
import { Recursion } from '../context';
|
|
3
|
-
import { union, some, recursion, precedence, surround, close,
|
|
3
|
+
import { union, some, recursion, precedence, focus, surround, close, fallback, lazy } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { text, str } from '../source';
|
|
6
|
-
import {
|
|
6
|
+
import { invalid } from '../util';
|
|
7
7
|
import { unshift, push } from 'spica/array';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
|
-
export const remark: RemarkParser = lazy(() =>
|
|
11
|
-
/\[(
|
|
12
|
-
|
|
13
|
-
([,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
([as, bs]) => bs && [unshift(as, bs)]),
|
|
26
|
-
([, fence]) => fence.length, {})));
|
|
10
|
+
export const remark: RemarkParser = lazy(() => fallback(surround(
|
|
11
|
+
str(/\[%(?=\s)/y),
|
|
12
|
+
precedence(4, recursion(Recursion.inline,
|
|
13
|
+
some(union([inline]), /\s%\]/y, [[/\s%\]/y, 4]]))),
|
|
14
|
+
close(text, str(`%]`)), true,
|
|
15
|
+
([as, bs = [], cs]) => [[
|
|
16
|
+
html('span', { class: 'remark' }, [
|
|
17
|
+
html('input', { type: 'checkbox' }),
|
|
18
|
+
html('span', defrag(push(unshift(as, bs), cs))),
|
|
19
|
+
]),
|
|
20
|
+
]],
|
|
21
|
+
([as, bs]) => bs && [unshift(as, bs)]),
|
|
22
|
+
focus(/\[%+(?=\s)/y, ({ context: { source } }) => [[
|
|
23
|
+
html('span', { class: 'invalid', ...invalid('remark', 'syntax', 'Invalid start symbol') }, source)
|
|
24
|
+
]])));
|
|
@@ -18,11 +18,11 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
18
18
|
return isTightNodeStart(ns) ? [ns] : undefined;
|
|
19
19
|
},
|
|
20
20
|
undefined,
|
|
21
|
-
[
|
|
21
|
+
[1 | Backtrack.bracket, 3 | Backtrack.ruby])),
|
|
22
22
|
dup(surround(
|
|
23
23
|
'(', text, ')',
|
|
24
24
|
false, undefined, undefined,
|
|
25
|
-
[
|
|
25
|
+
[1 | Backtrack.bracket, 3 | Backtrack.ruby])),
|
|
26
26
|
]),
|
|
27
27
|
([texts, rubies], context) => {
|
|
28
28
|
if (rubies === undefined) {
|
|
@@ -69,7 +69,7 @@ const text: RubyParser.TextParser = input => {
|
|
|
69
69
|
let state = false;
|
|
70
70
|
context.sequential = true;
|
|
71
71
|
for (let { position } = context; position < source.length; position = context.position) {
|
|
72
|
-
if (
|
|
72
|
+
if (/[$"`\[\](){}<>()[]{}]|\\?\n/yi.test(source.slice(position, position + 2))) break;
|
|
73
73
|
assert(source[position] !== '\n');
|
|
74
74
|
switch (source[position]) {
|
|
75
75
|
case '&': {
|
|
@@ -12,7 +12,7 @@ export const shortmedia: ShortMediaParser = constraint(State.media, rewrite(
|
|
|
12
12
|
false)));
|
|
13
13
|
|
|
14
14
|
export const lineshortmedia: ShortMediaParser.LineShortMediaParser = focus(
|
|
15
|
-
/(?<=^|[\r\n])
|
|
15
|
+
/(?<=^|[\r\n])!https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/y,
|
|
16
16
|
convert(
|
|
17
17
|
source => `!{ ${source.slice(1)} }`,
|
|
18
18
|
union([media]),
|
|
@@ -22,10 +22,10 @@ describe('Unit: parser/inline', () => {
|
|
|
22
22
|
it('nest', () => {
|
|
23
23
|
assert.deepStrictEqual(inspect(parser('あ(A)'), ctx), [['あ', '(', 'A', ')'], '']);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser('あ(い)'), ctx), [['あ', '<span class="paren">(い)</span>'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('* a*'), ctx), [['*', '
|
|
26
|
-
assert.deepStrictEqual(inspect(parser('** a**'), ctx), [['**', '
|
|
27
|
-
assert.deepStrictEqual(inspect(parser('*** a***'), ctx), [['***', '
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('**** a****'), ctx), [['****', '
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('* a*'), ctx), [['*', ' a', '*'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('** a**'), ctx), [['**', ' a', '**'], '']);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser('*** a***'), ctx), [['***', ' a', '***'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser('**** a****'), ctx), [['****', ' a', '****'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('*a**'), ctx), [['<em>a</em>', '*'], '']);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('*a**b'), ctx), [['*', 'a', '**', 'b'], '']);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('*a**b*'), ctx), [['<em>a**b</em>'], '']);
|
|
@@ -98,11 +98,11 @@ describe('Unit: parser/inline', () => {
|
|
|
98
98
|
assert.deepStrictEqual(inspect(parser('++\na\n++\n~~\nb\n~~\nc'), ctx), [['<ins><br>a</ins>', '<br>', '<del><br>b</del>', '<br>', 'c'], '']);
|
|
99
99
|
assert.deepStrictEqual(inspect(parser('[@a]'), ctx), [['[', '<a class="account" href="/@a">@a</a>', ']'], '']);
|
|
100
100
|
assert.deepStrictEqual(inspect(parser('[#1][#2]'), ctx), [['<a class="index" href="#index::1">1</a>', '<a class="index" href="#index::2">2</a>'], '']);
|
|
101
|
-
assert.deepStrictEqual(inspect(parser('[$1]'), ctx), [['[', '$
|
|
102
|
-
assert.deepStrictEqual(inspect(parser('[$1-2]'), ctx), [['[', '$
|
|
101
|
+
assert.deepStrictEqual(inspect(parser('[$1]'), ctx), [['[', '$1', ']'], '']);
|
|
102
|
+
assert.deepStrictEqual(inspect(parser('[$1-2]'), ctx), [['[', '$1-2', ']'], '']);
|
|
103
103
|
assert.deepStrictEqual(inspect(parser('[$-1][$-2]'), ctx), [['<a class="label" data-label="$-1">$-1</a>', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
104
104
|
assert.deepStrictEqual(inspect(parser('$-1, $-2'), ctx), [['<a class="label" data-label="$-1">$-1</a>', ',', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
105
|
-
assert.deepStrictEqual(inspect(parser('$-1 and $-2'), ctx), [['<a class="label" data-label="$-1">$-1</a>', '
|
|
105
|
+
assert.deepStrictEqual(inspect(parser('$-1 and $-2'), ctx), [['<a class="label" data-label="$-1">$-1</a>', ' and', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
106
106
|
assert.deepStrictEqual(inspect(parser('$$-1'), ctx), [['$', '<a class="label" data-label="$-1">$-1</a>'], '']);
|
|
107
107
|
assert.deepStrictEqual(inspect(parser('[[#a]]'), ctx), [['<sup class="reference"><span><a class="hashtag" href="/hashtags/a">#a</a></span></sup>'], '']);
|
|
108
108
|
assert.deepStrictEqual(inspect(parser('[[$-1]]'), ctx), [['<sup class="reference"><span><a class="label" data-label="$-1">$-1</a></span></sup>'], '']);
|
|
@@ -129,8 +129,8 @@ describe('Unit: parser/inline', () => {
|
|
|
129
129
|
assert.deepStrictEqual(inspect(parser('${a}'), ctx), [['$', '<a class="url" href="a">a</a>'], '']);
|
|
130
130
|
assert.deepStrictEqual(inspect(parser('${{a}}'), ctx), [['$', '<span class="template">{{a}}</span>'], '']);
|
|
131
131
|
assert.deepStrictEqual(inspect(parser('${{{a}}}'), ctx), [['$', '<span class="template">{{{a}}}</span>'], '']);
|
|
132
|
-
assert.deepStrictEqual(inspect(parser('Di$ney Micro$oft'), ctx), [['Di', '$
|
|
133
|
-
assert.deepStrictEqual(inspect(parser('Di$ney, Micro$oft'), ctx), [['Di', '$
|
|
132
|
+
assert.deepStrictEqual(inspect(parser('Di$ney Micro$oft'), ctx), [['Di', '$ney Micro', '$oft'], '']);
|
|
133
|
+
assert.deepStrictEqual(inspect(parser('Di$ney, Micro$oft'), ctx), [['Di', '$ney, Micro', '$oft'], '']);
|
|
134
134
|
assert.deepStrictEqual(inspect(parser('(((a))'), ctx), [['(', '<sup class="annotation"><span>a</span></sup>'], '']);
|
|
135
135
|
assert.deepStrictEqual(inspect(parser('((((a))'), ctx), [['(', '(', '<sup class="annotation"><span>a</span></sup>'], '']);
|
|
136
136
|
assert.deepStrictEqual(inspect(parser('((((a))))'), ctx), [['<sup class="annotation"><span><span class="paren">((a))</span></span></sup>'], '']);
|
|
@@ -165,16 +165,16 @@ describe('Unit: parser/inline', () => {
|
|
|
165
165
|
assert.deepStrictEqual(inspect(parser('"[% *"*"*'), ctx), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
|
|
166
166
|
assert.deepStrictEqual(inspect(parser('"[% "*"* %]'), ctx), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
|
|
167
167
|
assert.deepStrictEqual(inspect(parser('"{{""}}'), ctx), [['"', '{', '{', '"', '"', '}', '}'], '']);
|
|
168
|
-
assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(<bdi>)">http://host/(<bdi>)</a>', '
|
|
169
|
-
assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host/(<bdi>)</a>', '
|
|
168
|
+
assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(<bdi>)">http://host/(<bdi>)</a>', '</bdi', '>'], '']);
|
|
169
|
+
assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host/(<bdi>)</a>', '</bdi', '>'], '']);
|
|
170
170
|
assert.deepStrictEqual(inspect(parser('[#a|<bdi>]</bdi>'), ctx), [['[', '<a class="hashtag" href="/hashtags/a">#a</a>', '|', '<bdi>]</bdi>'], '']);
|
|
171
171
|
assert.deepStrictEqual(inspect(parser('[[#a|<bdi>]</bdi>'), ctx), [['[', '[', '<a class="hashtag" href="/hashtags/a">#a</a>', '|', '<bdi>]</bdi>'], '']);
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
it('uri', () => {
|
|
175
175
|
assert.deepStrictEqual(inspect(parser('\nhttp://host'), ctx), [['<br>', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
176
|
-
assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http
|
|
177
|
-
assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp
|
|
176
|
+
assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http:', '//host'], '']);
|
|
177
|
+
assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp:', '//host'], '']);
|
|
178
178
|
assert.deepStrictEqual(inspect(parser('?http://host'), ctx), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
179
179
|
assert.deepStrictEqual(inspect(parser('0!http://host'), ctx), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
180
180
|
assert.deepStrictEqual(inspect(parser('0?http://host'), ctx), [['0', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
@@ -196,7 +196,8 @@ describe('Unit: parser/inline', () => {
|
|
|
196
196
|
assert.deepStrictEqual(inspect(parser('*a@b*'), ctx), [['<em><a class="email" href="mailto:a@b">a@b</a></em>'], '']);
|
|
197
197
|
assert.deepStrictEqual(inspect(parser('(a@b)'), ctx), [['<span class="paren">(<a class="email" href="mailto:a@b">a@b</a>)</span>'], '']);
|
|
198
198
|
assert.deepStrictEqual(inspect(parser(' a@b'), ctx), [[' ', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
199
|
-
assert.deepStrictEqual(inspect(parser('++a
|
|
199
|
+
assert.deepStrictEqual(inspect(parser('++a@b++'), ctx), [['<ins><a class="email" href="mailto:a@b">a@b</a></ins>'], '']);
|
|
200
|
+
assert.deepStrictEqual(inspect(parser('++a++b@c++'), ctx), [['<ins>a</ins>', '<a class="email" href="mailto:b@c">b@c</a>', '++'], '']);
|
|
200
201
|
});
|
|
201
202
|
|
|
202
203
|
it('channel', () => {
|
|
@@ -209,7 +210,7 @@ describe('Unit: parser/inline', () => {
|
|
|
209
210
|
|
|
210
211
|
it('account', () => {
|
|
211
212
|
assert.deepStrictEqual(inspect(parser('@a'), ctx), [['<a class="account" href="/@a">@a</a>'], '']);
|
|
212
|
-
assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http', '
|
|
213
|
+
assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http', '://host'], '']);
|
|
213
214
|
assert.deepStrictEqual(inspect(parser('_@a'), ctx), [['_', '<a class="account" href="/@a">@a</a>'], '']);
|
|
214
215
|
assert.deepStrictEqual(inspect(parser('_@a_'), ctx), [['_', '<a class="account" href="/@a">@a</a>', '_'], '']);
|
|
215
216
|
assert.deepStrictEqual(inspect(parser('*@a*'), ctx), [['<em><a class="account" href="/@a">@a</a></em>'], '']);
|
|
@@ -219,21 +220,21 @@ describe('Unit: parser/inline', () => {
|
|
|
219
220
|
|
|
220
221
|
it('hashtag', () => {
|
|
221
222
|
assert.deepStrictEqual(inspect(parser('#a#'), ctx), [['#a', '#'], '']);
|
|
222
|
-
assert.deepStrictEqual(inspect(parser('#a#b'), ctx), [['#a', '#
|
|
223
|
+
assert.deepStrictEqual(inspect(parser('#a#b'), ctx), [['#a', '#b'], '']);
|
|
223
224
|
assert.deepStrictEqual(inspect(parser('#a'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
224
|
-
assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#http', '
|
|
225
|
+
assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#http', '://host'], '']);
|
|
225
226
|
assert.deepStrictEqual(inspect(parser('#a\nb\n#c\n[#d]'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>', '<br>', 'b', '<br>', '<a class="hashtag" href="/hashtags/c">#c</a>', '<br>', '<a class="index" href="#index::d">d</a>'], '']);
|
|
226
227
|
assert.deepStrictEqual(inspect(parser('##a'), ctx), [['##a'], '']);
|
|
227
228
|
assert.deepStrictEqual(inspect(parser('_#a'), ctx), [['_', '<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
228
229
|
assert.deepStrictEqual(inspect(parser('_#a_'), ctx), [['_', '<a class="hashtag" href="/hashtags/a">#a</a>', '_'], '']);
|
|
229
230
|
assert.deepStrictEqual(inspect(parser('_#a_b'), ctx), [['_', '<a class="hashtag" href="/hashtags/a_b">#a_b</a>'], '']);
|
|
230
231
|
assert.deepStrictEqual(inspect(parser('_#a_b_'), ctx), [['_', '<a class="hashtag" href="/hashtags/a_b">#a_b</a>', '_'], '']);
|
|
231
|
-
assert.deepStrictEqual(inspect(parser('a#b'), ctx), [['a', '#
|
|
232
|
-
assert.deepStrictEqual(inspect(parser('0a#b'), ctx), [['0a', '#
|
|
233
|
-
assert.deepStrictEqual(inspect(parser('あ#b'), ctx), [['あ', '#
|
|
234
|
-
assert.deepStrictEqual(inspect(parser('あい#b'), ctx), [['あい', '#
|
|
235
|
-
assert.deepStrictEqual(inspect(parser('0aあ#b'), ctx), [['0a', 'あ', '#
|
|
236
|
-
assert.deepStrictEqual(inspect(parser('0aあい#b'), ctx), [['0a', 'あい', '#
|
|
232
|
+
assert.deepStrictEqual(inspect(parser('a#b'), ctx), [['a', '#b'], '']);
|
|
233
|
+
assert.deepStrictEqual(inspect(parser('0a#b'), ctx), [['0a', '#b'], '']);
|
|
234
|
+
assert.deepStrictEqual(inspect(parser('あ#b'), ctx), [['あ', '#b'], '']);
|
|
235
|
+
assert.deepStrictEqual(inspect(parser('あい#b'), ctx), [['あい', '#b'], '']);
|
|
236
|
+
assert.deepStrictEqual(inspect(parser('0aあ#b'), ctx), [['0a', 'あ', '#b'], '']);
|
|
237
|
+
assert.deepStrictEqual(inspect(parser('0aあい#b'), ctx), [['0a', 'あい', '#b'], '']);
|
|
237
238
|
assert.deepStrictEqual(inspect(parser('「#あ」'), ctx), [['「', '<a class="hashtag" href="/hashtags/あ">#あ</a>', '」'], '']);
|
|
238
239
|
assert.deepStrictEqual(inspect(parser('a\n#b'), ctx), [['a', '<br>', '<a class="hashtag" href="/hashtags/b">#b</a>'], '']);
|
|
239
240
|
assert.deepStrictEqual(inspect(parser('a\\\n#b'), ctx), [['a', '<br>', '<a class="hashtag" href="/hashtags/b">#b</a>'], '']);
|
|
@@ -247,7 +248,7 @@ describe('Unit: parser/inline', () => {
|
|
|
247
248
|
it('hashnum', () => {
|
|
248
249
|
assert.deepStrictEqual(inspect(parser('#1'), ctx), [['<a class="hashnum">#1</a>'], '']);
|
|
249
250
|
assert.deepStrictEqual(inspect(parser(`#1'`), ctx), [[`<a class="hashnum">#1</a>`, `'`], '']);
|
|
250
|
-
assert.deepStrictEqual(inspect(parser('#1234567890@a'), ctx), [['#1234567890', '@
|
|
251
|
+
assert.deepStrictEqual(inspect(parser('#1234567890@a'), ctx), [['#1234567890', '@a'], '']);
|
|
251
252
|
assert.deepStrictEqual(inspect(parser('_#1'), ctx), [['_', '<a class="hashnum">#1</a>'], '']);
|
|
252
253
|
assert.deepStrictEqual(inspect(parser('_#1_'), ctx), [['_', '<a class="hashnum">#1</a>', '_'], '']);
|
|
253
254
|
assert.deepStrictEqual(inspect(parser('_#1_0'), ctx), [['_', '<a class="hashtag" href="/hashtags/1_0">#1_0</a>'], '']);
|
package/src/parser/inline.ts
CHANGED
|
@@ -55,22 +55,27 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
55
55
|
if (position === source.length) return;
|
|
56
56
|
switch (source.slice(position, position + 2)) {
|
|
57
57
|
case '((':
|
|
58
|
-
return annotation(input)
|
|
58
|
+
return annotation(input)
|
|
59
|
+
|| bracket(input);
|
|
59
60
|
case '[[':
|
|
60
61
|
return reference(input)
|
|
61
|
-
|| textlink(input)
|
|
62
|
+
|| textlink(input)
|
|
63
|
+
|| bracket(input);
|
|
62
64
|
case '{{':
|
|
63
|
-
return template(input)
|
|
65
|
+
return template(input)
|
|
66
|
+
|| bracket(input);
|
|
64
67
|
case '[%':
|
|
65
68
|
return remark(input)
|
|
66
|
-
|| textlink(input)
|
|
69
|
+
|| textlink(input)
|
|
70
|
+
|| bracket(input);
|
|
67
71
|
case '[#':
|
|
68
72
|
case '[$':
|
|
69
73
|
case '[:':
|
|
70
74
|
case '[^':
|
|
71
75
|
case '[|':
|
|
72
76
|
return extension(input)
|
|
73
|
-
|| textlink(input)
|
|
77
|
+
|| textlink(input)
|
|
78
|
+
|| bracket(input);
|
|
74
79
|
case '${':
|
|
75
80
|
return math(input);
|
|
76
81
|
case '++':
|
|
@@ -89,9 +94,11 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
89
94
|
switch (source[position]) {
|
|
90
95
|
case '[':
|
|
91
96
|
return textlink(input)
|
|
92
|
-
|| ruby(input)
|
|
97
|
+
|| ruby(input)
|
|
98
|
+
|| bracket(input);
|
|
93
99
|
case '{':
|
|
94
|
-
return textlink(input)
|
|
100
|
+
return textlink(input)
|
|
101
|
+
|| bracket(input);
|
|
95
102
|
case '<':
|
|
96
103
|
return html(input);
|
|
97
104
|
case '$':
|
|
@@ -104,9 +111,14 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
104
111
|
|| stars(input);
|
|
105
112
|
case '&':
|
|
106
113
|
return htmlentity(input);
|
|
114
|
+
case '(':
|
|
115
|
+
case '(':
|
|
116
|
+
case '[':
|
|
117
|
+
case '{':
|
|
118
|
+
case '"':
|
|
119
|
+
return bracket(input);
|
|
107
120
|
}
|
|
108
121
|
},
|
|
109
|
-
bracket,
|
|
110
122
|
autolink,
|
|
111
123
|
text
|
|
112
124
|
])) as any;
|
|
@@ -116,4 +128,4 @@ export { indexer } from './inline/extension/indexer';
|
|
|
116
128
|
export { dataindex } from './inline/extension/index';
|
|
117
129
|
export { medialink } from './inline/link';
|
|
118
130
|
export { media } from './inline/media';
|
|
119
|
-
export { shortmedia } from './inline/shortmedia';
|
|
131
|
+
export { shortmedia, lineshortmedia } from './inline/shortmedia';
|
package/src/parser/segment.ts
CHANGED
|
@@ -14,13 +14,31 @@ export const MAX_SEGMENT_SIZE = 100_000; // 100,000 bytes (Max value size of FDB
|
|
|
14
14
|
export const MAX_INPUT_SIZE = MAX_SEGMENT_SIZE * 10;
|
|
15
15
|
|
|
16
16
|
const parser: SegmentParser = union([
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
input => {
|
|
18
|
+
const { context: { source, position } } = input;
|
|
19
|
+
if (position === source.length) return;
|
|
20
|
+
switch (source.slice(position, position + 3)) {
|
|
21
|
+
case '~~~':
|
|
22
|
+
return extension(input);
|
|
23
|
+
case '```':
|
|
24
|
+
return codeblock(input);
|
|
25
|
+
}
|
|
26
|
+
switch (source.slice(position, position + 2)) {
|
|
27
|
+
case '$$':
|
|
28
|
+
return mathblock(input);
|
|
29
|
+
case '[$':
|
|
30
|
+
return extension(input);
|
|
31
|
+
}
|
|
32
|
+
switch (source[position]) {
|
|
33
|
+
case '#':
|
|
34
|
+
return heading(input);
|
|
35
|
+
case '$':
|
|
36
|
+
return extension(input);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
21
39
|
some(contentline, MAX_SEGMENT_SIZE + 1),
|
|
22
40
|
some(emptyline, MAX_SEGMENT_SIZE + 1),
|
|
23
|
-
]);
|
|
41
|
+
]) as any;
|
|
24
42
|
|
|
25
43
|
export function* segment(source: string): Generator<string, undefined, undefined> {
|
|
26
44
|
if (!validate(source, MAX_INPUT_SIZE)) return yield `${Command.Error}Too large input over ${MAX_INPUT_SIZE.toLocaleString('en')} bytes.\n${source.slice(0, 1001)}`;
|
|
@@ -15,7 +15,7 @@ describe('Unit: parser/source/escsource', () => {
|
|
|
15
15
|
it('basic', () => {
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('a'), ctx), [['a'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('ab'), ctx), [['ab'], '']);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09
|
|
18
|
+
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09あいAZaz'], '']);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
it('space', () => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { EscapableSourceParser } from '../source';
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { consume } from '../../combinator';
|
|
4
|
-
import { nonWhitespace,
|
|
4
|
+
import { nonWhitespace, isBlank, next } from './text';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
|
+
const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s(?:\$)|:\/\/)/g;
|
|
8
|
+
|
|
7
9
|
export const escsource: EscapableSourceParser = ({ context }) => {
|
|
8
10
|
const { source, position } = context;
|
|
9
11
|
if (position === source.length) return;
|
|
@@ -36,23 +38,13 @@ export const escsource: EscapableSourceParser = ({ context }) => {
|
|
|
36
38
|
default:
|
|
37
39
|
assert(char !== '\n');
|
|
38
40
|
if (context.sequential) return [[char]];
|
|
39
|
-
nonAlphanumeric.lastIndex = position + 1;
|
|
40
41
|
nonWhitespace.lastIndex = position + 1;
|
|
41
|
-
ASCII.lastIndex = position + 1;
|
|
42
42
|
const b = isBlank(source, position);
|
|
43
43
|
let i = b
|
|
44
44
|
? nonWhitespace.test(source)
|
|
45
45
|
? nonWhitespace.lastIndex - 1
|
|
46
46
|
: source.length
|
|
47
|
-
:
|
|
48
|
-
? nonAlphanumeric.test(source)
|
|
49
|
-
? nonAlphanumeric.lastIndex - 1
|
|
50
|
-
: source.length
|
|
51
|
-
: !isASCII(char)
|
|
52
|
-
? ASCII.test(source)
|
|
53
|
-
? ASCII.lastIndex - 1
|
|
54
|
-
: source.length
|
|
55
|
-
: position + 1;
|
|
47
|
+
: next(source, position, delimiter);
|
|
56
48
|
assert(i > position);
|
|
57
49
|
i -= position;
|
|
58
50
|
consume(i - 1, context);
|
|
@@ -15,7 +15,7 @@ describe('Unit: parser/source/text', () => {
|
|
|
15
15
|
it('basic', () => {
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('a'), ctx), [['a'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('ab'), ctx), [['ab'], '']);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09
|
|
18
|
+
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09あいAZaz'], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('a\nb'), ctx), [['a', '<br>', 'b'], '']);
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -41,18 +41,18 @@ describe('Unit: parser/source/text', () => {
|
|
|
41
41
|
assert.deepStrictEqual(inspect(parser(' \n'), ctx), [['<br>'], '']);
|
|
42
42
|
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
|
|
43
43
|
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
|
|
44
|
-
assert.deepStrictEqual(inspect(parser(' a'), ctx), [['
|
|
45
|
-
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', '
|
|
46
|
-
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', '
|
|
44
|
+
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' a'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
|
|
46
|
+
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
|
|
47
47
|
assert.deepStrictEqual(inspect(parser('a '), ctx), [['a'], '']);
|
|
48
48
|
assert.deepStrictEqual(inspect(parser('a '), ctx), [['a'], '']);
|
|
49
49
|
assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
|
|
50
50
|
assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
|
|
51
51
|
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
|
|
52
52
|
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
|
|
53
|
-
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a
|
|
54
|
-
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', '
|
|
55
|
-
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', '
|
|
53
|
+
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a b'], '']);
|
|
54
|
+
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it('hardbreak', () => {
|
|
@@ -76,45 +76,45 @@ describe('Unit: parser/source/text', () => {
|
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('account', () => {
|
|
79
|
-
assert.deepStrictEqual(inspect(parser('@0'), ctx), [['@
|
|
80
|
-
assert.deepStrictEqual(inspect(parser('_@0'), ctx), [['_', '@
|
|
81
|
-
assert.deepStrictEqual(inspect(parser('$@0'), ctx), [['$', '@
|
|
82
|
-
assert.deepStrictEqual(inspect(parser('+@0'), ctx), [['+', '@
|
|
83
|
-
assert.deepStrictEqual(inspect(parser('-@0'), ctx), [['-', '@
|
|
84
|
-
assert.deepStrictEqual(inspect(parser('0@0'), ctx), [['0', '@
|
|
85
|
-
assert.deepStrictEqual(inspect(parser('a@0'), ctx), [['a', '@
|
|
86
|
-
assert.deepStrictEqual(inspect(parser('A@0'), ctx), [['A', '@
|
|
87
|
-
assert.deepStrictEqual(inspect(parser('aA@0'), ctx), [['aA', '@
|
|
88
|
-
assert.deepStrictEqual(inspect(parser(' @0'), ctx), [[' ', '@
|
|
89
|
-
assert.deepStrictEqual(inspect(parser('@@0'), ctx), [['@', '@
|
|
79
|
+
assert.deepStrictEqual(inspect(parser('@0'), ctx), [['@0'], '']);
|
|
80
|
+
assert.deepStrictEqual(inspect(parser('_@0'), ctx), [['_', '@0'], '']);
|
|
81
|
+
assert.deepStrictEqual(inspect(parser('$@0'), ctx), [['$', '@0'], '']);
|
|
82
|
+
assert.deepStrictEqual(inspect(parser('+@0'), ctx), [['+', '@0'], '']);
|
|
83
|
+
assert.deepStrictEqual(inspect(parser('-@0'), ctx), [['-', '@0'], '']);
|
|
84
|
+
assert.deepStrictEqual(inspect(parser('0@0'), ctx), [['0', '@0'], '']);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('a@0'), ctx), [['a', '@0'], '']);
|
|
86
|
+
assert.deepStrictEqual(inspect(parser('A@0'), ctx), [['A', '@0'], '']);
|
|
87
|
+
assert.deepStrictEqual(inspect(parser('aA@0'), ctx), [['aA', '@0'], '']);
|
|
88
|
+
assert.deepStrictEqual(inspect(parser(' @0'), ctx), [[' ', '@0'], '']);
|
|
89
|
+
assert.deepStrictEqual(inspect(parser('@@0'), ctx), [['@', '@0'], '']);
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
it('hashtag', () => {
|
|
93
|
-
assert.deepStrictEqual(inspect(parser('#0'), ctx), [['#
|
|
94
|
-
assert.deepStrictEqual(inspect(parser('_#0'), ctx), [['_', '#
|
|
95
|
-
assert.deepStrictEqual(inspect(parser('$#0'), ctx), [['$', '#
|
|
96
|
-
assert.deepStrictEqual(inspect(parser('+#0'), ctx), [['+', '#
|
|
97
|
-
assert.deepStrictEqual(inspect(parser('-#0'), ctx), [['-', '#
|
|
98
|
-
assert.deepStrictEqual(inspect(parser('0#0'), ctx), [['0', '#
|
|
99
|
-
assert.deepStrictEqual(inspect(parser('a#0'), ctx), [['a', '#
|
|
100
|
-
assert.deepStrictEqual(inspect(parser('A#0'), ctx), [['A', '#
|
|
101
|
-
assert.deepStrictEqual(inspect(parser('aA#0'), ctx), [['aA', '#
|
|
102
|
-
assert.deepStrictEqual(inspect(parser(' #0'), ctx), [[' ', '#
|
|
103
|
-
assert.deepStrictEqual(inspect(parser('##0'), ctx), [['#', '#
|
|
93
|
+
assert.deepStrictEqual(inspect(parser('#0'), ctx), [['#0'], '']);
|
|
94
|
+
assert.deepStrictEqual(inspect(parser('_#0'), ctx), [['_', '#0'], '']);
|
|
95
|
+
assert.deepStrictEqual(inspect(parser('$#0'), ctx), [['$', '#0'], '']);
|
|
96
|
+
assert.deepStrictEqual(inspect(parser('+#0'), ctx), [['+', '#0'], '']);
|
|
97
|
+
assert.deepStrictEqual(inspect(parser('-#0'), ctx), [['-', '#0'], '']);
|
|
98
|
+
assert.deepStrictEqual(inspect(parser('0#0'), ctx), [['0', '#0'], '']);
|
|
99
|
+
assert.deepStrictEqual(inspect(parser('a#0'), ctx), [['a', '#0'], '']);
|
|
100
|
+
assert.deepStrictEqual(inspect(parser('A#0'), ctx), [['A', '#0'], '']);
|
|
101
|
+
assert.deepStrictEqual(inspect(parser('aA#0'), ctx), [['aA', '#0'], '']);
|
|
102
|
+
assert.deepStrictEqual(inspect(parser(' #0'), ctx), [[' ', '#0'], '']);
|
|
103
|
+
assert.deepStrictEqual(inspect(parser('##0'), ctx), [['#', '#0'], '']);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
it('anchor', () => {
|
|
107
|
-
assert.deepStrictEqual(inspect(parser('>>0'), ctx), [['>', '>
|
|
108
|
-
assert.deepStrictEqual(inspect(parser('_>>0'), ctx), [['_', '>', '>
|
|
109
|
-
assert.deepStrictEqual(inspect(parser('$>>0'), ctx), [['$', '>', '>
|
|
110
|
-
assert.deepStrictEqual(inspect(parser('+>>0'), ctx), [['+', '>', '>
|
|
111
|
-
assert.deepStrictEqual(inspect(parser('->>0'), ctx), [['-', '>', '>
|
|
112
|
-
assert.deepStrictEqual(inspect(parser('0>>0'), ctx), [['0', '>', '>
|
|
113
|
-
assert.deepStrictEqual(inspect(parser('a>>0'), ctx), [['a', '>', '>
|
|
114
|
-
assert.deepStrictEqual(inspect(parser('A>>0'), ctx), [['A', '>', '>
|
|
115
|
-
assert.deepStrictEqual(inspect(parser('aA>>0'), ctx), [['aA', '>', '>
|
|
116
|
-
assert.deepStrictEqual(inspect(parser(' >>0'), ctx), [[' ', '>', '>
|
|
117
|
-
assert.deepStrictEqual(inspect(parser('>>>>0'), ctx), [['>', '>', '>', '>
|
|
107
|
+
assert.deepStrictEqual(inspect(parser('>>0'), ctx), [['>', '>0'], '']);
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('_>>0'), ctx), [['_', '>', '>0'], '']);
|
|
109
|
+
assert.deepStrictEqual(inspect(parser('$>>0'), ctx), [['$', '>', '>0'], '']);
|
|
110
|
+
assert.deepStrictEqual(inspect(parser('+>>0'), ctx), [['+', '>', '>0'], '']);
|
|
111
|
+
assert.deepStrictEqual(inspect(parser('->>0'), ctx), [['-', '>', '>0'], '']);
|
|
112
|
+
assert.deepStrictEqual(inspect(parser('0>>0'), ctx), [['0', '>', '>0'], '']);
|
|
113
|
+
assert.deepStrictEqual(inspect(parser('a>>0'), ctx), [['a', '>', '>0'], '']);
|
|
114
|
+
assert.deepStrictEqual(inspect(parser('A>>0'), ctx), [['A', '>', '>0'], '']);
|
|
115
|
+
assert.deepStrictEqual(inspect(parser('aA>>0'), ctx), [['aA', '>', '>0'], '']);
|
|
116
|
+
assert.deepStrictEqual(inspect(parser(' >>0'), ctx), [[' ', '>', '>0'], '']);
|
|
117
|
+
assert.deepStrictEqual(inspect(parser('>>>>0'), ctx), [['>', '>', '>', '>0'], '']);
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
});
|
|
@@ -3,10 +3,8 @@ import { Command } from '../context';
|
|
|
3
3
|
import { union, consume, focus } from '../../combinator';
|
|
4
4
|
import { html } from 'typed-dom/dom';
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const delimiter = /(?=[\\!@#$&"`\[\](){}<>()[]{}*%|\r\n]|([+~=])\1|\/{3}|\s(?:\\?(?:$|\s)|[$%])|:\/\/)/g;
|
|
7
7
|
export const nonWhitespace = /[\S\r\n]/g;
|
|
8
|
-
export const nonAlphanumeric = /[^0-9A-Za-z]/g;
|
|
9
|
-
export const ASCII = /[\x00-\x7F()[]{}]/g;
|
|
10
8
|
|
|
11
9
|
export const text: TextParser = input => {
|
|
12
10
|
const { context } = input;
|
|
@@ -39,23 +37,13 @@ export const text: TextParser = input => {
|
|
|
39
37
|
default:
|
|
40
38
|
assert(char !== '\n');
|
|
41
39
|
if (context.sequential) return [[char]];
|
|
42
|
-
nonAlphanumeric.lastIndex = position + 1;
|
|
43
40
|
nonWhitespace.lastIndex = position + 1;
|
|
44
|
-
ASCII.lastIndex = position + 1;
|
|
45
41
|
const b = isBlank(source, position);
|
|
46
42
|
let i = b
|
|
47
43
|
? nonWhitespace.test(source)
|
|
48
44
|
? nonWhitespace.lastIndex - 1
|
|
49
45
|
: source.length
|
|
50
|
-
:
|
|
51
|
-
? nonAlphanumeric.test(source)
|
|
52
|
-
? nonAlphanumeric.lastIndex - 1
|
|
53
|
-
: source.length
|
|
54
|
-
: !isASCII(char)
|
|
55
|
-
? ASCII.test(source)
|
|
56
|
-
? ASCII.lastIndex - 1
|
|
57
|
-
: source.length
|
|
58
|
-
: position + 1;
|
|
46
|
+
: next(source, position, delimiter);
|
|
59
47
|
assert(i > position);
|
|
60
48
|
const lineend = 0
|
|
61
49
|
|| b && i === source.length
|
|
@@ -82,24 +70,89 @@ export const linebreak: LinebreakParser = focus(/[\r\n]/y, union([
|
|
|
82
70
|
text,
|
|
83
71
|
])) as LinebreakParser;
|
|
84
72
|
|
|
73
|
+
export function next(source: string, position: number, delimiter: RegExp): number {
|
|
74
|
+
delimiter.lastIndex = position + 1;
|
|
75
|
+
delimiter.test(source);
|
|
76
|
+
let index = delimiter.lastIndex;
|
|
77
|
+
if (index === 0) return source.length;
|
|
78
|
+
assert(index > position);
|
|
79
|
+
const char = source[index];
|
|
80
|
+
switch (char) {
|
|
81
|
+
case ':':
|
|
82
|
+
index = backToUrlHead(source, position, index);
|
|
83
|
+
break;
|
|
84
|
+
case '@':
|
|
85
|
+
index = backToEmailHead(source, position, index);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
assert(index > position);
|
|
89
|
+
return index;
|
|
90
|
+
}
|
|
91
|
+
export function backToUrlHead(source: string, position: number, index: number): number {
|
|
92
|
+
const delim = index;
|
|
93
|
+
let state = false;
|
|
94
|
+
let offset = 0;
|
|
95
|
+
for (let i = index; --i > position;) {
|
|
96
|
+
index = i;
|
|
97
|
+
const char = source[i];
|
|
98
|
+
if (state) switch (char) {
|
|
99
|
+
case '.':
|
|
100
|
+
case '+':
|
|
101
|
+
case '-':
|
|
102
|
+
state = false;
|
|
103
|
+
offset = 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (isAlphanumeric(char)) {
|
|
107
|
+
state = true;
|
|
108
|
+
offset = 0;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (index === position + 1 && offset === 0 && isAlphanumeric(source[index - 1])) {
|
|
114
|
+
return delim;
|
|
115
|
+
}
|
|
116
|
+
return index + offset;
|
|
117
|
+
}
|
|
118
|
+
export function backToEmailHead(source: string, position: number, index: number): number {
|
|
119
|
+
const delim = index;
|
|
120
|
+
let state = false;
|
|
121
|
+
let offset = 0;
|
|
122
|
+
for (let i = index; --i > position;) {
|
|
123
|
+
index = i;
|
|
124
|
+
const char = source[i];
|
|
125
|
+
if (state) switch (char) {
|
|
126
|
+
case '_':
|
|
127
|
+
case '.':
|
|
128
|
+
case '+':
|
|
129
|
+
case '-':
|
|
130
|
+
state = false;
|
|
131
|
+
offset = 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (isAlphanumeric(char)) {
|
|
135
|
+
state = true;
|
|
136
|
+
offset = 0;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
if (index === position + 1 && offset === 0 && isAlphanumeric(source[index - 1])) {
|
|
142
|
+
return delim;
|
|
143
|
+
}
|
|
144
|
+
return index + offset;
|
|
145
|
+
}
|
|
146
|
+
|
|
85
147
|
const blank = /\s(?:$|\s|\\\n)/y;
|
|
86
148
|
export function isBlank(source: string, position: number): boolean {
|
|
87
149
|
blank.lastIndex = position;
|
|
88
150
|
return blank.test(source);
|
|
89
151
|
}
|
|
90
|
-
|
|
91
|
-
export function isAlphanumeric(char: string): boolean {
|
|
152
|
+
function isAlphanumeric(char: string): boolean {
|
|
92
153
|
assert(char.length === 1);
|
|
93
154
|
if (char < '0' || '\x7F' < char) return false;
|
|
94
155
|
return '0' <= char && char <= '9'
|
|
95
156
|
|| 'a' <= char && char <= 'z'
|
|
96
157
|
|| 'A' <= char && char <= 'Z';
|
|
97
158
|
}
|
|
98
|
-
|
|
99
|
-
export function isASCII(char: string): boolean {
|
|
100
|
-
assert(char.length === 1);
|
|
101
|
-
return char <= '\x7F'
|
|
102
|
-
|| char === '(' || char === ')'
|
|
103
|
-
|| char === '[' || char === ']'
|
|
104
|
-
|| char === '{' || char === '}';
|
|
105
|
-
}
|