securemark 0.295.8 → 0.296.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/design.md +1 -1
- package/dist/index.js +268 -282
- package/package.json +1 -1
- package/src/combinator/control/constraint/contract.ts +5 -21
- package/src/combinator/data/parser/context.ts +3 -1
- package/src/combinator/data/parser/sequence.ts +3 -3
- package/src/combinator/data/parser.ts +7 -2
- package/src/parser/api/normalize.ts +10 -7
- package/src/parser/block/extension/figbase.test.ts +3 -0
- package/src/parser/block/extension/figbase.ts +1 -1
- package/src/parser/block/paragraph.test.ts +2 -2
- package/src/parser/block/reply/cite.ts +2 -1
- package/src/parser/block/reply/quote.ts +2 -1
- package/src/parser/block/reply.ts +2 -1
- package/src/parser/inline/annotation.test.ts +4 -5
- package/src/parser/inline/annotation.ts +2 -2
- package/src/parser/inline/emphasis.ts +3 -3
- package/src/parser/inline/emstrong.ts +4 -4
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/extension/indexer.ts +3 -3
- package/src/parser/inline/extension/placeholder.ts +2 -2
- package/src/parser/inline/html.ts +2 -1
- package/src/parser/inline/htmlentity.test.ts +1 -1
- package/src/parser/inline/htmlentity.ts +10 -5
- package/src/parser/inline/italic.ts +2 -2
- package/src/parser/inline/link.test.ts +5 -4
- package/src/parser/inline/link.ts +6 -4
- package/src/parser/inline/mark.ts +2 -2
- package/src/parser/inline/media.test.ts +5 -2
- package/src/parser/inline/media.ts +9 -4
- package/src/parser/inline/reference.test.ts +5 -6
- package/src/parser/inline/reference.ts +2 -2
- package/src/parser/inline/remark.ts +1 -1
- package/src/parser/inline/strong.ts +3 -3
- package/src/parser/node.ts +17 -0
- package/src/parser/source/str.ts +9 -7
- package/src/parser/source/text.ts +4 -4
- package/src/parser/visibility.ts +53 -75
- /package/src/combinator/data/{data.ts → node.ts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MediaParser } from '../inline';
|
|
2
2
|
import { State, Recursion, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
+
import { Flag } from '../node';
|
|
4
5
|
import { union, inits, tails, some, consume, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
5
6
|
import { uri, option as linkoption, resolve, decode, parse } from './link';
|
|
6
7
|
import { attributes } from './html';
|
|
@@ -50,10 +51,14 @@ export const media: MediaParser = lazy(() => constraint(State.media, open(
|
|
|
50
51
|
nodes =>
|
|
51
52
|
nodes.length === 1
|
|
52
53
|
? new List<Node<List<Node<string>>>>([new Node(new List([new Node('')])), nodes.delete(nodes.head!)])
|
|
53
|
-
: new List<Node<List<Node<string>>>>([new Node(new List([new Node(nodes.head!.value.foldl((acc, { value }) => acc + value, ''))])), nodes.delete(nodes.last!)])),
|
|
54
|
-
([{ value: [{ value: text }] }, { value: params }], context) => {
|
|
55
|
-
if (
|
|
56
|
-
|
|
54
|
+
: new List<Node<List<Node<string>>>>([new Node(new List([new Node(nodes.head!.value.foldl((acc, { value }) => acc + value, ''), nodes.head!.value.head?.flags)])), nodes.delete(nodes.last!)])),
|
|
55
|
+
([{ value: [{ value: text, flags }] }, { value: params }], context) => {
|
|
56
|
+
if (flags & Flag.invisible) return;
|
|
57
|
+
if (text) {
|
|
58
|
+
const tmp = text;
|
|
59
|
+
text = text.trim();
|
|
60
|
+
if (text === '' || text[0] !== tmp[0]) return;
|
|
61
|
+
}
|
|
57
62
|
consume(100, context);
|
|
58
63
|
if (params.last!.value === Command.Cancel) {
|
|
59
64
|
params.pop();
|
|
@@ -19,7 +19,10 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
19
19
|
assert.deepStrictEqual(inspect(parser, input('[[(]]', new Context())), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser, input('[[[%]]', new Context())), undefined);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser, input('[[ ]]', new Context())), undefined);
|
|
22
|
-
assert.deepStrictEqual(inspect(parser, input('[[
|
|
22
|
+
assert.deepStrictEqual(inspect(parser, input('[[ a]]', new Context())), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser, input('[[ a ]]', new Context())), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser, input('[[\\ a]]', new Context())), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser, input('[[<wbr>a]]', new Context())), undefined);
|
|
23
26
|
assert.deepStrictEqual(inspect(parser, input('[[\n]]', new Context())), undefined);
|
|
24
27
|
assert.deepStrictEqual(inspect(parser, input('[[\na]]', new Context())), undefined);
|
|
25
28
|
assert.deepStrictEqual(inspect(parser, input('[[\\\na]]', new Context())), undefined);
|
|
@@ -35,10 +38,6 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
35
38
|
});
|
|
36
39
|
|
|
37
40
|
it('basic', () => {
|
|
38
|
-
assert.deepStrictEqual(inspect(parser, input('[[ a]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
39
|
-
assert.deepStrictEqual(inspect(parser, input('[[ a ]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
40
|
-
assert.deepStrictEqual(inspect(parser, input('[[\\ a]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
41
|
-
assert.deepStrictEqual(inspect(parser, input('[[<wbr>a]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
42
41
|
assert.deepStrictEqual(inspect(parser, input('[[a]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
43
42
|
assert.deepStrictEqual(inspect(parser, input('[[a ]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
44
43
|
assert.deepStrictEqual(inspect(parser, input('[[a ]]', new Context())), [['<sup class="reference"><span>a</span></sup>'], '']);
|
|
@@ -81,7 +80,7 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
81
80
|
assert.deepStrictEqual(inspect(parser, input('[[^A| b]]', new Context())), [['<sup class="reference" data-abbr="A"><span>b</span></sup>'], '']);
|
|
82
81
|
assert.deepStrictEqual(inspect(parser, input('[[^A| ]]', new Context())), undefined);
|
|
83
82
|
assert.deepStrictEqual(inspect(parser, input('[[^A|<wbr>]]', new Context())), undefined);
|
|
84
|
-
assert.deepStrictEqual(inspect(parser, input('[[^A|<wbr>b]]', new Context())),
|
|
83
|
+
assert.deepStrictEqual(inspect(parser, input('[[^A|<wbr>b]]', new Context())), undefined);
|
|
85
84
|
assert.deepStrictEqual(inspect(parser, input('[[^A|^]]', new Context())), [['<sup class="reference" data-abbr="A"><span>^</span></sup>'], '']);
|
|
86
85
|
assert.deepStrictEqual(inspect(parser, input('[[^A|^B]]', new Context())), [['<sup class="reference" data-abbr="A"><span>^B</span></sup>'], '']);
|
|
87
86
|
assert.deepStrictEqual(inspect(parser, input('[[^1]]', new Context())), [['<sup class="invalid"><span>^1</span></sup>'], '']);
|
|
@@ -5,7 +5,7 @@ import { union, subsequence, some, precedence, state, constraint, surround, isBa
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { textlink } from './link';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
|
|
9
9
|
import { unwrap, invalid } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
|
|
|
14
14
|
precedence(1, state(State.annotation | State.reference,
|
|
15
15
|
subsequence([
|
|
16
16
|
abbr,
|
|
17
|
-
|
|
17
|
+
beforeNonblank(some(inline, ']', [[']', 1]])),
|
|
18
18
|
]))),
|
|
19
19
|
']]',
|
|
20
20
|
false,
|
|
@@ -11,7 +11,7 @@ export const remark: RemarkParser = lazy(() => fallback(surround(
|
|
|
11
11
|
str(/\[%(?=[ \n])/y),
|
|
12
12
|
precedence(3, recursion(Recursion.inline,
|
|
13
13
|
some(union([inline]), /[ \n]%\]/y, [[/[ \n]%\]/y, 3]]))),
|
|
14
|
-
close(text, str(
|
|
14
|
+
close(text, str('%]')),
|
|
15
15
|
true, [],
|
|
16
16
|
([as, bs = new List(), cs]) => new List([
|
|
17
17
|
new Node(html('span', { class: 'remark' }, [
|
|
@@ -5,14 +5,14 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { emphasis } from './emphasis';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblank, afterNonblank } from '../visibility';
|
|
9
9
|
import { unwrap } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const strong: StrongParser = lazy(() => surround(
|
|
13
|
-
str(
|
|
13
|
+
str('**', (source, position, range) => !source.startsWith('*', position + range)),
|
|
14
14
|
precedence(0, recursion(Recursion.inline,
|
|
15
|
-
|
|
15
|
+
beforeNonblank(some(union([
|
|
16
16
|
some(inline, '*', afterNonblank),
|
|
17
17
|
emphasis,
|
|
18
18
|
]))))),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
2
|
+
|
|
3
|
+
export const enum Flag {
|
|
4
|
+
none,
|
|
5
|
+
invisible,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const isInvisibleHTMLEntityName: (name: string) => boolean = eval([
|
|
9
|
+
'name => {',
|
|
10
|
+
'switch(name){',
|
|
11
|
+
invisibleHTMLEntityNames.map(name => `case '${name}':`).join(''),
|
|
12
|
+
'return true;',
|
|
13
|
+
'default:',
|
|
14
|
+
'return false;',
|
|
15
|
+
'}',
|
|
16
|
+
'}',
|
|
17
|
+
].join(''));
|
package/src/parser/source/str.ts
CHANGED
|
@@ -2,21 +2,23 @@ import { StrParser } from '../source';
|
|
|
2
2
|
import { Parser, List, Node } from '../../combinator/data/parser';
|
|
3
3
|
import { matcher } from '../../combinator';
|
|
4
4
|
|
|
5
|
-
export function str(pattern: string | RegExp): StrParser;
|
|
6
|
-
export function str(pattern: string | RegExp): Parser<string> {
|
|
7
|
-
return matcher(pattern, true);
|
|
5
|
+
export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): StrParser;
|
|
6
|
+
export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
|
|
7
|
+
return matcher(pattern, true, verify);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function strs(pattern: string): StrParser;
|
|
11
|
-
export function strs(pattern: string): Parser<string> {
|
|
10
|
+
export function strs(pattern: string, limit?: number): StrParser;
|
|
11
|
+
export function strs(pattern: string, limit: number = -1): Parser<string> {
|
|
12
12
|
assert(pattern);
|
|
13
13
|
return ({ context }) => {
|
|
14
14
|
const { source } = context;
|
|
15
15
|
let acc = '';
|
|
16
|
-
for (; context.position < source.length && source.startsWith(pattern, context.position);) {
|
|
16
|
+
for (let i = 0; i !== limit && context.position < source.length && source.startsWith(pattern, context.position); ++i) {
|
|
17
17
|
acc += pattern;
|
|
18
18
|
context.position += pattern.length;
|
|
19
19
|
}
|
|
20
|
-
return
|
|
20
|
+
return acc
|
|
21
|
+
? new List([new Node(acc)])
|
|
22
|
+
: undefined;
|
|
21
23
|
};
|
|
22
24
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { TextParser, TxtParser } from '../source';
|
|
2
2
|
import { State, Command } from '../context';
|
|
3
|
+
import { Flag } from '../node';
|
|
3
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
5
|
import { union, consume } from '../../combinator';
|
|
5
6
|
import { html } from 'typed-dom/dom';
|
|
@@ -32,7 +33,7 @@ export const text: TextParser = input => {
|
|
|
32
33
|
return new List();
|
|
33
34
|
case '\n':
|
|
34
35
|
context.linebreak ||= source.length - position;
|
|
35
|
-
return new List([new Node(html('br'))]);
|
|
36
|
+
return new List([new Node(html('br'), Flag.invisible)]);
|
|
36
37
|
default:
|
|
37
38
|
assert(char !== '\n');
|
|
38
39
|
if (context.sequential) return new List([new Node(char)]);
|
|
@@ -52,9 +53,8 @@ export const text: TextParser = input => {
|
|
|
52
53
|
consume(i - 1, context);
|
|
53
54
|
context.position += i - 1;
|
|
54
55
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
: new List([new Node(source.slice(position, context.position))]);
|
|
56
|
+
if (position === context.position || s && !linestart || lineend) return new List();
|
|
57
|
+
return new List([new Node(source.slice(position, context.position))]);
|
|
58
58
|
}
|
|
59
59
|
};
|
|
60
60
|
|
package/src/parser/visibility.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Parser, Input, List, Node, failsafe } from '../combinator/data/parser';
|
|
2
2
|
import { Context, Command } from './context';
|
|
3
|
+
import { Flag } from './node';
|
|
3
4
|
import { convert, fmap } from '../combinator';
|
|
4
|
-
import { unsafehtmlentity } from './inline/htmlentity';
|
|
5
5
|
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
6
6
|
|
|
7
|
-
namespace
|
|
7
|
+
namespace invisible {
|
|
8
8
|
export const line = new RegExp(
|
|
9
9
|
/((?:^|\n)[^\S\n]*(?=\S))((?:[^\S\n]|\\(?=$|\s)|&IHN;|<wbr ?>)+(?=$|\n))/g.source
|
|
10
10
|
.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
@@ -13,12 +13,15 @@ namespace blank {
|
|
|
13
13
|
/(?:[^\S\n]|\\(?=$|\s)|&IHN;|<wbr ?>)+/y.source
|
|
14
14
|
.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
15
15
|
'y');
|
|
16
|
+
export const unit = new RegExp(
|
|
17
|
+
/(?:[^\S\n]|\\(?=$|\s)|&IHN;|<wbr ?>)/y.source
|
|
18
|
+
.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
19
|
+
'y');
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
export function visualize<P extends Parser
|
|
19
|
-
export function visualize<N extends HTMLElement | string>(parser: Parser<N>): Parser<N> {
|
|
22
|
+
export function visualize<P extends Parser>(parser: P): P {
|
|
20
23
|
return convert(
|
|
21
|
-
source => source.replace(
|
|
24
|
+
source => source.replace(invisible.line, `$1${Command.Escape}$2`),
|
|
22
25
|
parser);
|
|
23
26
|
}
|
|
24
27
|
|
|
@@ -42,114 +45,86 @@ function nonblankWith(delimiter: string | RegExp): RegExp {
|
|
|
42
45
|
].join(''), 'y');
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
//export function looseStart<P extends Parser<HTMLElement | string>>(parser: P
|
|
46
|
-
//export function looseStart<N extends HTMLElement | string>(parser: Parser<N
|
|
48
|
+
//export function looseStart<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
49
|
+
//export function looseStart<N extends HTMLElement | string>(parser: Parser<N>): Parser<N> {
|
|
47
50
|
// return input =>
|
|
48
|
-
// isLooseStart(input
|
|
51
|
+
// isLooseStart(input)
|
|
49
52
|
// ? parser(input)
|
|
50
53
|
// : undefined;
|
|
51
54
|
//}
|
|
52
|
-
//const isLooseStart = reduce(({ source, context }: Input<Context
|
|
53
|
-
// return isTightStart({ source: source.replace(
|
|
54
|
-
//}, ({ source }
|
|
55
|
+
//const isLooseStart = reduce(({ source, context }: Input<Context>): boolean => {
|
|
56
|
+
// return isTightStart({ source: source.replace(invisible.start, ''), context });
|
|
57
|
+
//}, ({ source }) => `${source}${Command.Separator}`);
|
|
55
58
|
|
|
56
|
-
export function
|
|
57
|
-
export function
|
|
59
|
+
export function beforeNonblank<P extends Parser>(parser: P): P;
|
|
60
|
+
export function beforeNonblank<N>(parser: Parser<N>): Parser<N, Context> {
|
|
58
61
|
return input =>
|
|
59
|
-
isTightStart(input
|
|
62
|
+
isTightStart(input)
|
|
60
63
|
? parser(input)
|
|
61
64
|
: undefined;
|
|
62
65
|
}
|
|
63
|
-
function isTightStart(input: Input<Context
|
|
66
|
+
function isTightStart(input: Input<Context>): boolean {
|
|
64
67
|
const { context } = input;
|
|
65
68
|
const { source, position } = context;
|
|
66
69
|
if (position === source.length) return true;
|
|
67
|
-
if (except && source.startsWith(except, position)) return false;
|
|
68
70
|
switch (source[position]) {
|
|
69
71
|
case ' ':
|
|
70
72
|
case ' ':
|
|
71
73
|
case '\t':
|
|
72
74
|
case '\n':
|
|
73
75
|
return false;
|
|
74
|
-
case '\\':
|
|
75
|
-
return source[position + 1]?.trimStart() !== '';
|
|
76
|
-
case '&':
|
|
77
|
-
switch (true) {
|
|
78
|
-
case source.length - position > 2
|
|
79
|
-
&& source[position + 1] !== ' '
|
|
80
|
-
&& unsafehtmlentity(input)?.head?.value.trimStart() === '':
|
|
81
|
-
context.position = position;
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
context.position = position;
|
|
85
|
-
return true;
|
|
86
|
-
case '<':
|
|
87
|
-
switch (true) {
|
|
88
|
-
case source.length - position >= 5
|
|
89
|
-
&& source.startsWith('<wbr', position)
|
|
90
|
-
&& (source[position + 4] === '>' || source.startsWith(' >', position + 4)):
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
return true;
|
|
94
76
|
default:
|
|
95
|
-
|
|
77
|
+
const reg = invisible.unit;
|
|
78
|
+
reg.lastIndex = position;
|
|
79
|
+
return !reg.test(source);
|
|
96
80
|
}
|
|
97
81
|
}
|
|
98
82
|
|
|
99
83
|
export function isLooseNodeStart(nodes: List<Node<HTMLElement | string>>): boolean {
|
|
100
84
|
if (nodes.length === 0) return true;
|
|
101
|
-
for (const
|
|
85
|
+
for (const node of nodes) {
|
|
102
86
|
if (isVisible(node)) return true;
|
|
103
|
-
if (typeof node === 'object' && node.tagName === 'BR') break;
|
|
87
|
+
if (typeof node.value === 'object' && node.value.tagName === 'BR') break;
|
|
104
88
|
}
|
|
105
89
|
return false;
|
|
106
90
|
}
|
|
107
91
|
export function isTightNodeStart(nodes: List<Node<HTMLElement | string>>): boolean {
|
|
108
92
|
if (nodes.length === 0) return true;
|
|
109
|
-
return isVisible(nodes.head
|
|
93
|
+
return isVisible(nodes.head!, 0);
|
|
110
94
|
}
|
|
111
95
|
//export function isTightNodeEnd(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
112
96
|
// if (nodes.length === 0) return true;
|
|
113
97
|
// return isVisible(nodes.at(-1)!, -1);
|
|
114
98
|
//}
|
|
115
|
-
function isVisible(node: HTMLElement | string
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
default:
|
|
128
|
-
return char.trimStart() !== '';
|
|
129
|
-
}
|
|
99
|
+
function isVisible({ value: node, flags }: Node<HTMLElement | string>, strpos?: number): boolean {
|
|
100
|
+
if (flags & Flag.invisible) return false;
|
|
101
|
+
if (typeof node !== 'string') return true;
|
|
102
|
+
const str = node && strpos !== undefined
|
|
103
|
+
? node[strpos >= 0 ? strpos : node.length + strpos]
|
|
104
|
+
: node;
|
|
105
|
+
switch (str) {
|
|
106
|
+
case '':
|
|
107
|
+
case ' ':
|
|
108
|
+
case '\t':
|
|
109
|
+
case '\n':
|
|
110
|
+
return false;
|
|
130
111
|
default:
|
|
131
|
-
|
|
132
|
-
case 'BR':
|
|
133
|
-
case 'WBR':
|
|
134
|
-
return false;
|
|
135
|
-
default:
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
112
|
+
return str.trimStart() !== '';
|
|
138
113
|
}
|
|
139
114
|
}
|
|
140
115
|
|
|
141
|
-
//
|
|
116
|
+
// 終端が必要な場合は無駄な後方トリムを避けるためtrimBlankStart+trimBlankNodeEndで処理する。
|
|
142
117
|
export function trimBlank<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
143
118
|
export function trimBlank<N extends HTMLElement | string>(parser: Parser<N>): Parser<N> {
|
|
144
119
|
return trimBlankStart(trimBlankEnd(parser));
|
|
145
120
|
}
|
|
146
|
-
|
|
147
|
-
|
|
121
|
+
function trimBlankStart<P extends Parser>(parser: P): P;
|
|
122
|
+
function trimBlankStart<N>(parser: Parser<N>): Parser<N> {
|
|
148
123
|
return failsafe(input => {
|
|
149
124
|
const { context } = input;
|
|
150
125
|
const { source, position } = context;
|
|
151
126
|
if (position === source.length) return;
|
|
152
|
-
const reg =
|
|
127
|
+
const reg = invisible.start;
|
|
153
128
|
reg.lastIndex = position;
|
|
154
129
|
reg.test(source);
|
|
155
130
|
context.position = reg.lastIndex || position;
|
|
@@ -182,21 +157,24 @@ export function trimBlankEnd<N extends HTMLElement>(parser: Parser<N>): Parser<s
|
|
|
182
157
|
// return nodes;
|
|
183
158
|
//}
|
|
184
159
|
export function trimBlankNodeEnd<N extends HTMLElement>(nodes: List<Node<string | N>>): List<Node<string | N>> {
|
|
185
|
-
const skip = nodes.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (typeof node.value === 'string') {
|
|
160
|
+
const skip = nodes.last && ~nodes.last.flags & Flag.invisible && typeof nodes.last.value === 'object'
|
|
161
|
+
? nodes.last.value.className === 'indexer'
|
|
162
|
+
: false;
|
|
163
|
+
for (let node = skip ? nodes.last?.prev : nodes.last; node;) {
|
|
164
|
+
const visible = ~node.flags & Flag.invisible;
|
|
165
|
+
if (visible && typeof node.value === 'string') {
|
|
192
166
|
const str = node.value.trimEnd();
|
|
193
167
|
if (str.length > 0) {
|
|
194
168
|
node.value = str;
|
|
195
169
|
break;
|
|
196
170
|
}
|
|
197
171
|
}
|
|
198
|
-
|
|
172
|
+
else if (visible) {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
const target = node;
|
|
176
|
+
node = node.prev;
|
|
177
|
+
nodes.delete(target);
|
|
199
178
|
}
|
|
200
|
-
skip && nodes.push(skip);
|
|
201
179
|
return nodes;
|
|
202
180
|
}
|
|
File without changes
|