securemark 0.290.2 → 0.291.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 +4 -0
- package/design.md +48 -2
- package/dist/index.js +215 -121
- package/markdown.d.ts +6 -17
- package/package.json +1 -1
- package/src/combinator/control/manipulation/surround.ts +17 -13
- package/src/combinator/data/parser/context/delimiter.ts +2 -2
- package/src/combinator/data/parser/context.ts +4 -3
- package/src/combinator/data/parser/some.ts +3 -3
- package/src/combinator/data/parser.ts +5 -3
- package/src/parser/api/parse.test.ts +34 -30
- package/src/parser/block/dlist.ts +1 -1
- package/src/parser/block/heading.ts +2 -2
- package/src/parser/block/mediablock.ts +2 -2
- package/src/parser/block/pagebreak.ts +1 -1
- package/src/parser/block/reply.ts +1 -1
- package/src/parser/block.ts +3 -1
- package/src/parser/header.ts +1 -1
- package/src/parser/inline/annotation.ts +4 -5
- package/src/parser/inline/autolink/account.ts +1 -1
- package/src/parser/inline/autolink/anchor.ts +1 -1
- package/src/parser/inline/autolink/channel.ts +1 -1
- package/src/parser/inline/autolink/email.ts +1 -1
- package/src/parser/inline/autolink/hashnum.ts +1 -1
- package/src/parser/inline/autolink/hashtag.ts +1 -1
- package/src/parser/inline/autolink/url.test.ts +8 -2
- package/src/parser/inline/autolink/url.ts +5 -6
- package/src/parser/inline/bracket.ts +25 -3
- package/src/parser/inline/code.ts +2 -2
- package/src/parser/inline/extension/index.ts +42 -26
- package/src/parser/inline/extension/indexee.ts +6 -3
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/inline/html.test.ts +22 -19
- package/src/parser/inline/html.ts +82 -78
- package/src/parser/inline/link.ts +12 -9
- package/src/parser/inline/mark.ts +1 -1
- package/src/parser/inline/math.test.ts +1 -0
- package/src/parser/inline/math.ts +18 -9
- package/src/parser/inline/media.test.ts +3 -3
- package/src/parser/inline/media.ts +14 -6
- package/src/parser/inline/reference.ts +67 -10
- package/src/parser/inline/ruby.ts +6 -5
- package/src/parser/inline/shortmedia.ts +1 -1
- package/src/parser/inline.ts +4 -19
- package/src/parser/segment.test.ts +3 -2
- package/src/parser/segment.ts +2 -2
- package/src/parser/source/escapable.ts +1 -1
- package/src/parser/source/text.ts +2 -2
- package/src/parser/source/unescapable.ts +1 -1
- package/src/parser/util.ts +14 -4
- package/src/parser/visibility.ts +1 -0
|
@@ -103,9 +103,9 @@ describe('Unit: parser/inline/media', () => {
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
it('attribute', () => {
|
|
106
|
-
assert.deepStrictEqual(inspect(parser('![]{/ __proto__}')), [['<a href="/" target="_blank"><img class="
|
|
107
|
-
assert.deepStrictEqual(inspect(parser('![]{/ constructor}')), [['<a href="/" target="_blank"><img class="
|
|
108
|
-
assert.deepStrictEqual(inspect(parser('![]{/ aspect-ratio}')), [['<a href="/" target="_blank"><img class="
|
|
106
|
+
assert.deepStrictEqual(inspect(parser('![]{/ __proto__}')), [['<a href="/" target="_blank"><img class="invalid" data-src="/" alt="/"></a>'], '']);
|
|
107
|
+
assert.deepStrictEqual(inspect(parser('![]{/ constructor}')), [['<a href="/" target="_blank"><img class="invalid" data-src="/" alt="/"></a>'], '']);
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('![]{/ aspect-ratio}')), [['<a href="/" target="_blank"><img class="invalid" data-src="/" alt="/"></a>'], '']);
|
|
109
109
|
assert.deepStrictEqual(inspect(parser('![]{/ nofollow}')), [['<a href="/" rel="nofollow" target="_blank"><img class="media" data-src="/" alt="/"></a>'], '']);
|
|
110
110
|
assert.deepStrictEqual(inspect(parser('![]{/ width="4" height="3"}')), [['<a href="/" target="_blank"><img class="media" data-src="/" alt="/" width="4" height="3"></a>'], '']);
|
|
111
111
|
assert.deepStrictEqual(inspect(parser('![]{/ 4x3}')), [['<a href="/" target="_blank"><img class="media" data-src="/" alt="/" width="4" height="3"></a>'], '']);
|
|
@@ -7,7 +7,6 @@ import { unsafehtmlentity } from './htmlentity';
|
|
|
7
7
|
import { txt, linebreak, str } from '../source';
|
|
8
8
|
import { invalid } from '../util';
|
|
9
9
|
import { ReadonlyURL } from 'spica/url';
|
|
10
|
-
import { push } from 'spica/array';
|
|
11
10
|
import { html, define } from 'typed-dom/dom';
|
|
12
11
|
|
|
13
12
|
const optspec = {
|
|
@@ -18,7 +17,7 @@ const optspec = {
|
|
|
18
17
|
} as const;
|
|
19
18
|
Object.setPrototypeOf(optspec, null);
|
|
20
19
|
|
|
21
|
-
export const media: MediaParser = lazy(() => constraint(State.media,
|
|
20
|
+
export const media: MediaParser = lazy(() => constraint(State.media, validate(['![', '!{'], creation(10, open(
|
|
22
21
|
'!',
|
|
23
22
|
bind(verify(fmap(tails([
|
|
24
23
|
dup(surround(
|
|
@@ -31,7 +30,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
|
|
|
31
30
|
']',
|
|
32
31
|
true,
|
|
33
32
|
([, ns = []], rest, context) =>
|
|
34
|
-
context.linebreak ===
|
|
33
|
+
context.linebreak === 0
|
|
35
34
|
? [ns, rest]
|
|
36
35
|
: undefined,
|
|
37
36
|
undefined,
|
|
@@ -68,7 +67,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
|
|
|
68
67
|
el.setAttribute('alt', text);
|
|
69
68
|
if (!sanitize(el, uri)) return [[el], rest];
|
|
70
69
|
assert(!el.matches('.invalid'));
|
|
71
|
-
define(el, attributes('media',
|
|
70
|
+
define(el, attributes('media', optspec, params));
|
|
72
71
|
assert(el.matches('img') || !el.matches('.invalid'));
|
|
73
72
|
// Awaiting the generic support for attr().
|
|
74
73
|
if (el.hasAttribute('aspect-ratio')) {
|
|
@@ -99,8 +98,17 @@ const bracket: MediaParser.TextParser.BracketParser = lazy(() => recursion(Recur
|
|
|
99
98
|
])));
|
|
100
99
|
|
|
101
100
|
const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
surround(
|
|
102
|
+
open(/^[^\S\n]+/, str(/^[1-9][0-9]*/)),
|
|
103
|
+
str(/^[x:]/),
|
|
104
|
+
str(/^[1-9][0-9]*(?=[^\S\n]|})/),
|
|
105
|
+
false,
|
|
106
|
+
([[a], [b], [c]], rest) => [
|
|
107
|
+
b === 'x'
|
|
108
|
+
? [`width="${a}"`, `height="${c}"`]
|
|
109
|
+
: [`aspect-ratio="${a}/${c}"`],
|
|
110
|
+
rest
|
|
111
|
+
]),
|
|
104
112
|
linkoption,
|
|
105
113
|
]));
|
|
106
114
|
|
|
@@ -1,30 +1,87 @@
|
|
|
1
1
|
import { ReferenceParser } from '../inline';
|
|
2
2
|
import { State, Backtrack, Command } from '../context';
|
|
3
|
-
import {
|
|
3
|
+
import { eval, exec } from '../../combinator/data/parser';
|
|
4
|
+
import { union, subsequence, some, precedence, state, constraint, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
|
|
4
5
|
import { inline } from '../inline';
|
|
6
|
+
import { textlink } from './link';
|
|
5
7
|
import { str } from '../source';
|
|
6
8
|
import { blank, trimBlankStart, trimBlankNodeEnd } from '../visibility';
|
|
7
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
|
-
import { unshift } from 'spica/array';
|
|
10
|
+
import { unshift, push } from 'spica/array';
|
|
9
11
|
import { invalid } from '../util';
|
|
10
12
|
|
|
11
|
-
export const reference: ReferenceParser = lazy(() => constraint(State.reference,
|
|
13
|
+
export const reference: ReferenceParser = lazy(() => constraint(State.reference, surround(
|
|
12
14
|
str('[['),
|
|
13
|
-
precedence(1, state(State.annotation | State.reference
|
|
15
|
+
precedence(1, state(State.annotation | State.reference,
|
|
14
16
|
subsequence([
|
|
15
17
|
abbr,
|
|
16
18
|
trimBlankStart(some(inline, ']', [[']', 1]])),
|
|
17
19
|
]))),
|
|
18
20
|
']]',
|
|
19
21
|
false,
|
|
20
|
-
([, ns], rest, context) =>
|
|
21
|
-
context.linebreak ===
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
([, ns], rest, context) => {
|
|
23
|
+
if (context.linebreak === 0) {
|
|
24
|
+
return [[html('sup', attributes(ns), [html('span', defrag(trimBlankNodeEnd(ns)))])], rest];
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const head = context.recent!.reduce((a, b) => a + b.length, rest.length);
|
|
28
|
+
setBacktrack(context, [2 | Backtrack.link], head, 2);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
25
31
|
([as, bs], rest, context) => {
|
|
32
|
+
const { recent } = context;
|
|
33
|
+
const head = recent!.reduce((a, b) => a + b.length, rest.length);
|
|
26
34
|
if (rest[0] !== ']') {
|
|
27
|
-
setBacktrack(context, [2 | Backtrack.bracket],
|
|
35
|
+
setBacktrack(context, [2 | Backtrack.bracket], head, 2);
|
|
36
|
+
}
|
|
37
|
+
else if (context.linebreak! > 0) {
|
|
38
|
+
setBacktrack(context, [2 | Backtrack.link], head, 2);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
assert(rest[0] === ']');
|
|
42
|
+
if (context.state! & State.annotation) {
|
|
43
|
+
push(bs, [rest[0]]);
|
|
44
|
+
}
|
|
45
|
+
const source = rest.slice(1);
|
|
46
|
+
let result: ReturnType<typeof textlink>;
|
|
47
|
+
if (source[0] !== '{') {
|
|
48
|
+
setBacktrack(context, [2 | Backtrack.link], head - 1);
|
|
49
|
+
result = [[], source];
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
assert(source.length > 0);
|
|
53
|
+
result = !isBacktrack(context, [1 | Backtrack.link], source)
|
|
54
|
+
? textlink({ source, context })
|
|
55
|
+
: undefined;
|
|
56
|
+
context.recent = recent;
|
|
57
|
+
if (!result) {
|
|
58
|
+
setBacktrack(context, [2 | Backtrack.link], head - 1);
|
|
59
|
+
result = [[], source];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
assert(result);
|
|
63
|
+
if (exec(result) === '') {
|
|
64
|
+
setBacktrack(context, [2 | Backtrack.link], head);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
assert(context.state! ^ State.link);
|
|
68
|
+
const next = surround(
|
|
69
|
+
'',
|
|
70
|
+
some(inline, ']', [[']', 1]]),
|
|
71
|
+
str(']'),
|
|
72
|
+
true,
|
|
73
|
+
([, cs = [], ds], rest) =>
|
|
74
|
+
[push(cs, ds), rest],
|
|
75
|
+
([, cs = []], rest) => {
|
|
76
|
+
setBacktrack(context, [2 | Backtrack.link], head);
|
|
77
|
+
return [cs, rest];
|
|
78
|
+
})
|
|
79
|
+
({ source: exec(result), context });
|
|
80
|
+
if (context.state! & State.annotation && next) {
|
|
81
|
+
push(push(bs, eval(result)), eval(next));
|
|
82
|
+
rest = exec(next);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
28
85
|
}
|
|
29
86
|
return context.state! & State.annotation
|
|
30
87
|
? [unshift(as, bs), rest]
|
|
@@ -18,15 +18,16 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
18
18
|
return isTightNodeStart(ns) ? [ns, rest] : undefined;
|
|
19
19
|
},
|
|
20
20
|
undefined,
|
|
21
|
-
[3 | Backtrack.ruby
|
|
21
|
+
[3 | Backtrack.ruby, 1 | Backtrack.bracket])),
|
|
22
22
|
dup(surround(
|
|
23
23
|
'(', rtext, ')',
|
|
24
24
|
false, undefined, undefined,
|
|
25
|
-
[3 | Backtrack.ruby
|
|
25
|
+
[3 | Backtrack.ruby, 1 | Backtrack.bracket])),
|
|
26
26
|
]),
|
|
27
27
|
([texts, rubies], rest, context) => {
|
|
28
28
|
if (rubies === undefined) {
|
|
29
|
-
|
|
29
|
+
const head = context.recent!.reduce((a, b) => a + b.length, rest.length);
|
|
30
|
+
return void setBacktrack(context, [2 | Backtrack.ruby], head);
|
|
30
31
|
}
|
|
31
32
|
switch (true) {
|
|
32
33
|
case rubies.length <= texts.length:
|
|
@@ -65,7 +66,7 @@ const rtext: RubyParser.TextParser = ({ source, context }) => {
|
|
|
65
66
|
const acc = [''];
|
|
66
67
|
let state = false;
|
|
67
68
|
while (source !== '') {
|
|
68
|
-
if (!/^(?:\\[^\n]|[^\\[\](){}<>"
|
|
69
|
+
if (!/^(?:\\[^\n]|[^\\[\](){}<>"$#\n])/.test(source)) break;
|
|
69
70
|
assert(source[0] !== '\n');
|
|
70
71
|
switch (source[0]) {
|
|
71
72
|
// @ts-expect-error
|
|
@@ -73,7 +74,7 @@ const rtext: RubyParser.TextParser = ({ source, context }) => {
|
|
|
73
74
|
const result = unsafehtmlentity({ source, context });
|
|
74
75
|
if (result) {
|
|
75
76
|
acc[acc.length - 1] += eval(result)[0];
|
|
76
|
-
source = exec(result
|
|
77
|
+
source = exec(result) ?? source.slice(1);
|
|
77
78
|
state ||= acc.at(-1)!.trimStart() !== '';
|
|
78
79
|
continue;
|
|
79
80
|
}
|
|
@@ -5,7 +5,7 @@ import { url } from './autolink/url';
|
|
|
5
5
|
import { media } from './media';
|
|
6
6
|
import { linebreak } from '../source';
|
|
7
7
|
|
|
8
|
-
export const shortmedia: ShortMediaParser = constraint(State.media,
|
|
8
|
+
export const shortmedia: ShortMediaParser = constraint(State.media, rewrite(
|
|
9
9
|
open('!', url),
|
|
10
10
|
convert(
|
|
11
11
|
source => `!{ ${source.slice(1)} }`,
|
package/src/parser/inline.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../markdown';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, lazy } from '../combinator';
|
|
3
3
|
import { annotation } from './inline/annotation';
|
|
4
4
|
import { reference } from './inline/reference';
|
|
5
5
|
import { template } from './inline/template';
|
|
@@ -47,12 +47,10 @@ export import ShortMediaParser = InlineParser.ShortMediaParser;
|
|
|
47
47
|
export import BracketParser = InlineParser.BracketParser;
|
|
48
48
|
export import AutolinkParser = InlineParser.AutolinkParser;
|
|
49
49
|
|
|
50
|
-
export const inline: InlineParser = lazy(() =>
|
|
50
|
+
export const inline: InlineParser = lazy(() => union([
|
|
51
51
|
input => {
|
|
52
|
-
const { source
|
|
52
|
+
const { source } = input;
|
|
53
53
|
if (source === '') return;
|
|
54
|
-
context.depth ??= 0;
|
|
55
|
-
++context.depth;
|
|
56
54
|
switch (source.slice(0, 2)) {
|
|
57
55
|
case '((':
|
|
58
56
|
return annotation(input);
|
|
@@ -106,20 +104,7 @@ export const inline: InlineParser = lazy(() => verify(union([
|
|
|
106
104
|
bracket,
|
|
107
105
|
autolink,
|
|
108
106
|
text
|
|
109
|
-
])
|
|
110
|
-
--context.depth!;
|
|
111
|
-
assert([rest]);
|
|
112
|
-
// ヒープを効率的に削除可能な場合は削除する。
|
|
113
|
-
// ヒープサイズは括弧類など特定の構文が完成しなかった場合にしか増加しないため
|
|
114
|
-
// ブロックごとに平均数ノード以下となることから削除せずとも平均的にはあまり影響はない。
|
|
115
|
-
//if (context.depth === 0) {
|
|
116
|
-
// const { backtracks } = context;
|
|
117
|
-
// while (backtracks.peek()?.key! > rest.length) {
|
|
118
|
-
// backtracks.extract();
|
|
119
|
-
// }
|
|
120
|
-
//}
|
|
121
|
-
return true;
|
|
122
|
-
})) as any;
|
|
107
|
+
])) as any;
|
|
123
108
|
|
|
124
109
|
export { indexee } from './inline/extension/indexee';
|
|
125
110
|
export { indexer } from './inline/extension/indexer';
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { segment } from './segment';
|
|
2
|
+
import { Command } from './context';
|
|
2
3
|
|
|
3
4
|
describe('Unit: parser/segment', () => {
|
|
4
5
|
describe('segment', () => {
|
|
5
6
|
it('huge input', () => {
|
|
6
7
|
const result = segment(`${'\n'.repeat(10 * 1000 ** 2)}`).next().value?.split('\n', 1)[0];
|
|
7
|
-
assert(result?.startsWith(
|
|
8
|
+
assert(result?.startsWith(`${Command.Error}Too large input`));
|
|
8
9
|
});
|
|
9
10
|
|
|
10
11
|
it('huge segment', () => {
|
|
11
12
|
const result = segment(`${'\n'.repeat(1000 ** 2 - 1)}`).next().value?.split('\n', 1)[0];
|
|
12
|
-
assert(result?.startsWith(
|
|
13
|
+
assert(result?.startsWith(`${Command.Error}Too large segment`));
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
it('basic', () => {
|
package/src/parser/segment.ts
CHANGED
|
@@ -18,8 +18,8 @@ const parser: SegmentParser = union([
|
|
|
18
18
|
codeblock,
|
|
19
19
|
mathblock,
|
|
20
20
|
extension,
|
|
21
|
-
some(contentline, MAX_SEGMENT_SIZE
|
|
22
|
-
some(emptyline, MAX_SEGMENT_SIZE
|
|
21
|
+
some(contentline, MAX_SEGMENT_SIZE + 1),
|
|
22
|
+
some(emptyline, MAX_SEGMENT_SIZE + 1),
|
|
23
23
|
]);
|
|
24
24
|
|
|
25
25
|
export function* segment(source: string): Generator<string, undefined, undefined> {
|
|
@@ -34,7 +34,7 @@ export const escsource: EscapableSourceParser = ({ source, context }) => {
|
|
|
34
34
|
return [[source.slice(0, 2)], source.slice(2)];
|
|
35
35
|
}
|
|
36
36
|
case '\n':
|
|
37
|
-
context.linebreak
|
|
37
|
+
context.linebreak ||= source.length;
|
|
38
38
|
return [[html('br')], source.slice(1)];
|
|
39
39
|
default:
|
|
40
40
|
assert(source[0] !== '\n');
|
|
@@ -4,7 +4,7 @@ import { union, consume, focus } from '../../combinator';
|
|
|
4
4
|
import { str } from './str';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
|
-
export const delimiter = /[\s\x00-\x7F
|
|
7
|
+
export const delimiter = /[\s\x00-\x7F()[]{}]|\S#|[0-9A-Za-z]>/u;
|
|
8
8
|
export const nonWhitespace = /[\S\n]|$/u;
|
|
9
9
|
export const nonAlphanumeric = /[^0-9A-Za-z]|\S#|[0-9A-Za-z]>|$/u;
|
|
10
10
|
const repeat = str(/^(.)\1*/);
|
|
@@ -36,7 +36,7 @@ export const text: TextParser = ({ source, context }) => {
|
|
|
36
36
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
37
37
|
}
|
|
38
38
|
case '\n':
|
|
39
|
-
context.linebreak
|
|
39
|
+
context.linebreak ||= source.length;
|
|
40
40
|
return [[html('br')], source.slice(1)];
|
|
41
41
|
case '*':
|
|
42
42
|
case '`':
|
|
@@ -22,7 +22,7 @@ export const unescsource: UnescapableSourceParser = ({ source, context }) => {
|
|
|
22
22
|
consume(1, context);
|
|
23
23
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
24
24
|
case '\n':
|
|
25
|
-
context.linebreak
|
|
25
|
+
context.linebreak ||= source.length;
|
|
26
26
|
return [[html('br')], source.slice(1)];
|
|
27
27
|
default:
|
|
28
28
|
assert(source[0] !== '\n');
|
package/src/parser/util.ts
CHANGED
|
@@ -4,12 +4,22 @@ import { Parser, Result, Ctx, Node, Context, eval, exec } from '../combinator/da
|
|
|
4
4
|
import { convert } from '../combinator';
|
|
5
5
|
import { define } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
|
-
export function lineable<P extends Parser<HTMLElement | string>>(parser: P,
|
|
8
|
-
export function lineable<N extends HTMLElement | string>(parser: Parser<N>,
|
|
7
|
+
export function lineable<P extends Parser<HTMLElement | string>>(parser: P, trim?: 0 | 1 | -1): P;
|
|
8
|
+
export function lineable<N extends HTMLElement | string>(parser: Parser<N>, trim = -1): Parser<N> {
|
|
9
9
|
return convert(
|
|
10
|
-
source => `\r${
|
|
10
|
+
source => `\r${
|
|
11
|
+
trim === 0
|
|
12
|
+
? source
|
|
13
|
+
: trim > 0
|
|
14
|
+
? source.at(-1) === '\n'
|
|
15
|
+
? source
|
|
16
|
+
: source + '\n'
|
|
17
|
+
: source.at(-1) === '\n'
|
|
18
|
+
? source.slice(0, -1)
|
|
19
|
+
: source
|
|
20
|
+
}`,
|
|
11
21
|
parser,
|
|
12
|
-
|
|
22
|
+
trim === 0);
|
|
13
23
|
}
|
|
14
24
|
|
|
15
25
|
export function repeat<P extends Parser<HTMLElement | string>>(symbol: string, parser: P, cons: (nodes: Node<P>[], context: Context<P>) => Node<P>[], termination?: (acc: Node<P>[][], rest: string, prefix: number, postfix: number, state: boolean) => Result<string | Node<P>>): P;
|
package/src/parser/visibility.ts
CHANGED
|
@@ -51,6 +51,7 @@ export function blankWith(starts: '' | '\n', delimiter?: string | RegExp): RegEx
|
|
|
51
51
|
return new RegExp(String.raw
|
|
52
52
|
`^(?:(?=${starts})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr[^\S\n]*>)${
|
|
53
53
|
// 空行除去
|
|
54
|
+
// 完全な空行はエスケープ済みなので再帰的バックトラックにはならない。
|
|
54
55
|
starts && '+'
|
|
55
56
|
})?${
|
|
56
57
|
typeof delimiter === 'string'
|