securemark 0.300.0 → 0.300.1
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/dist/index.js +197 -113
- package/package.json +1 -1
- package/src/api/bind.ts +2 -2
- package/src/api/parse.ts +2 -2
- package/src/combinator/control/inits.ts +13 -4
- package/src/combinator/control/sequence.ts +3 -1
- package/src/combinator/control/state.ts +1 -10
- package/src/combinator/control/union.ts +16 -3
- package/src/combinator/parser.ts +18 -8
- package/src/combinator/process/fence.ts +3 -3
- package/src/combinator/process/surround.ts +2 -0
- package/src/parser/block/codeblock.test.ts +0 -2
- package/src/parser/block/codeblock.ts +3 -3
- package/src/parser/block/extension/aside.test.ts +0 -1
- package/src/parser/block/extension/aside.ts +1 -1
- package/src/parser/block/extension/example.test.ts +0 -2
- package/src/parser/block/extension/example.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +0 -4
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.test.ts +0 -1
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/placeholder.ts +3 -3
- package/src/parser/block/extension/table.test.ts +0 -1
- package/src/parser/block/extension/table.ts +3 -3
- package/src/parser/block/mathblock.test.ts +0 -2
- package/src/parser/block/mathblock.ts +3 -3
- package/src/parser/context.ts +9 -12
- package/src/parser/document.ts +1 -1
- package/src/parser/inline/autolink/url.ts +4 -4
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/media.ts +4 -4
- package/src/parser/inline/ruby.ts +45 -8
- package/src/parser/inline/template.ts +4 -4
- package/src/parser/source/escapable.ts +0 -1
- package/src/parser/source/text.ts +14 -43
- package/src/parser/source/unescapable.ts +0 -1
- package/src/parser/source/whitespace.ts +36 -0
- package/src/parser/source.ts +1 -0
- package/src/parser/visibility.ts +2 -1
|
@@ -3,7 +3,7 @@ import { Input, Backtrack } from '../context';
|
|
|
3
3
|
import { Parser, Result, List, Node } from '../../combinator/parser';
|
|
4
4
|
import { union, inits, always, backtrack, surround, setBacktrack, dup, lazy, bind } from '../../combinator';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
|
-
import { txt } from '../source';
|
|
6
|
+
import { txt, isWhitespace } from '../source';
|
|
7
7
|
import { isNonblankNodeStart } from '../visibility';
|
|
8
8
|
import { unwrap } from '../util';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -63,8 +63,6 @@ export const ruby: RubyParser = lazy(() => backtrack(bind(
|
|
|
63
63
|
}
|
|
64
64
|
})));
|
|
65
65
|
|
|
66
|
-
const delimiter = /[$"`\[\](){}<>()[]{}|]|\\?\r?\n/y;
|
|
67
|
-
|
|
68
66
|
interface Memory {
|
|
69
67
|
position: number;
|
|
70
68
|
state: boolean;
|
|
@@ -72,7 +70,7 @@ interface Memory {
|
|
|
72
70
|
}
|
|
73
71
|
const text: RubyParser.TextParser = always<Parser<string, Input<Memory>>>([
|
|
74
72
|
(input, output) => {
|
|
75
|
-
input.
|
|
73
|
+
input.whitespace = true;
|
|
76
74
|
input.memory = {
|
|
77
75
|
position: 0,
|
|
78
76
|
state: false,
|
|
@@ -83,7 +81,7 @@ const text: RubyParser.TextParser = always<Parser<string, Input<Memory>>>([
|
|
|
83
81
|
() => loop,
|
|
84
82
|
(input, output) => {
|
|
85
83
|
const { memory } = input;
|
|
86
|
-
input.
|
|
84
|
+
input.whitespace = false;
|
|
87
85
|
return memory.state || memory.nodes.last!.value.trimStart() !== ''
|
|
88
86
|
? output.import(memory.nodes)
|
|
89
87
|
: undefined;
|
|
@@ -94,10 +92,9 @@ const loop: Result<string, Input<Memory>> = [
|
|
|
94
92
|
const { source, memory } = input;
|
|
95
93
|
for (let { position } = input; ; position = input.position) {
|
|
96
94
|
if (position === source.length) return Result.skip;
|
|
97
|
-
|
|
98
|
-
if (delimiter.test(source)) return Result.skip;
|
|
95
|
+
if (isDelimiter(source, position)) return Result.skip;
|
|
99
96
|
assert(source[position] !== '\n');
|
|
100
|
-
if (source[position]
|
|
97
|
+
if (!isWhitespace(source[position])) break;
|
|
101
98
|
memory.state ||= memory.nodes.last!.value.trimStart() !== '';
|
|
102
99
|
memory.nodes.push(new Node(''));
|
|
103
100
|
input.position += 1;
|
|
@@ -124,3 +121,43 @@ function* zip<N extends Node<unknown>>(a: List<N>, b: List<N>): Iterable<[N | un
|
|
|
124
121
|
yield [ra.value, rb.value];
|
|
125
122
|
}
|
|
126
123
|
}
|
|
124
|
+
|
|
125
|
+
function isDelimiter(source: string, position: number): boolean {
|
|
126
|
+
switch (source[position]) {
|
|
127
|
+
case '$':
|
|
128
|
+
case '"':
|
|
129
|
+
case '`':
|
|
130
|
+
case '[':
|
|
131
|
+
case ']':
|
|
132
|
+
case '(':
|
|
133
|
+
case ')':
|
|
134
|
+
case '{':
|
|
135
|
+
case '}':
|
|
136
|
+
case '<':
|
|
137
|
+
case '>':
|
|
138
|
+
case '(':
|
|
139
|
+
case ')':
|
|
140
|
+
case '[':
|
|
141
|
+
case ']':
|
|
142
|
+
case '{':
|
|
143
|
+
case '}':
|
|
144
|
+
case '|':
|
|
145
|
+
return true;
|
|
146
|
+
case '\\':
|
|
147
|
+
switch (source[position + 1]) {
|
|
148
|
+
case '\r':
|
|
149
|
+
return source[position + 2] === '\n';
|
|
150
|
+
case '\n':
|
|
151
|
+
return true;
|
|
152
|
+
default:
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
case '\r':
|
|
156
|
+
return source[position + 1] === '\n';
|
|
157
|
+
case '\n':
|
|
158
|
+
return true;
|
|
159
|
+
default:
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
assert(false);
|
|
163
|
+
}
|
|
@@ -25,15 +25,15 @@ export const template: TemplateParser = lazy(() => backtrack(surround(
|
|
|
25
25
|
input.source.slice(input.position - input.range, input.position)))))));
|
|
26
26
|
|
|
27
27
|
const bracket: TemplateParser.BracketParser = lazy(() => union([
|
|
28
|
-
surround(str('('), recursion(Recursion.
|
|
28
|
+
surround(str('('), recursion(Recursion.bracket, some(union([bracket, escsource]), ')')), str(')'),
|
|
29
29
|
true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
|
|
30
|
-
surround(str('['), recursion(Recursion.
|
|
30
|
+
surround(str('['), recursion(Recursion.bracket, some(union([bracket, escsource]), ']')), str(']'),
|
|
31
31
|
true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
|
|
32
|
-
surround(str('{'), recursion(Recursion.
|
|
32
|
+
surround(str('{'), recursion(Recursion.bracket, some(union([bracket, escsource]), '}')), str('}'),
|
|
33
33
|
true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
|
|
34
34
|
surround(
|
|
35
35
|
str('"'),
|
|
36
|
-
precedence(2, recursion(Recursion.
|
|
36
|
+
precedence(2, recursion(Recursion.bracket, some(escsource, /["\n]/y, [['"', 2], ['\n', 3]]))),
|
|
37
37
|
str('"'),
|
|
38
38
|
true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
|
|
39
39
|
]));
|
|
@@ -34,7 +34,6 @@ export const escsource: EscapableSourceParser = (input, output) => {
|
|
|
34
34
|
return output.append(new Node(html('br'), Flag.blank));
|
|
35
35
|
default:
|
|
36
36
|
assert(char !== '\n');
|
|
37
|
-
if (input.sequential) return output.append(new Node(char));
|
|
38
37
|
let i = seek(source, position);
|
|
39
38
|
assert(i > position);
|
|
40
39
|
i -= position;
|
|
@@ -3,6 +3,7 @@ import { Result, Node } from '../../combinator/parser';
|
|
|
3
3
|
import { union, spend } from '../../combinator';
|
|
4
4
|
import { State, Command } from '../context';
|
|
5
5
|
import { Flag } from '../node';
|
|
6
|
+
import { isWhitespace } from './whitespace';
|
|
6
7
|
import { html } from 'typed-dom/dom';
|
|
7
8
|
|
|
8
9
|
export const nonWhitespace = /[^ \t ]/g;
|
|
@@ -35,14 +36,13 @@ export const text: TextParser = (input, output) => {
|
|
|
35
36
|
return output.append(new Node(html('br'), Flag.blank));
|
|
36
37
|
default:
|
|
37
38
|
assert(char !== '\n');
|
|
38
|
-
if (input.sequential) return output.append(new Node(char));
|
|
39
39
|
nonWhitespace.lastIndex = position + 1;
|
|
40
40
|
const s = canSkip(source, position);
|
|
41
41
|
let i = s
|
|
42
42
|
? nonWhitespace.test(source)
|
|
43
43
|
? nonWhitespace.lastIndex - 1
|
|
44
44
|
: source.length
|
|
45
|
-
: next(source, position, state);
|
|
45
|
+
: next(source, position, input.whitespace, state);
|
|
46
46
|
assert(i > position);
|
|
47
47
|
const lineend = 0
|
|
48
48
|
|| s && i === source.length
|
|
@@ -68,28 +68,15 @@ export function canSkip(source: string, position: number): boolean {
|
|
|
68
68
|
if (position + 1 === source.length) return true;
|
|
69
69
|
return isWhitespace(source[position + 1], true);
|
|
70
70
|
}
|
|
71
|
-
function isWhitespace(char: string, linebreak: boolean): boolean {
|
|
72
|
-
switch (char) {
|
|
73
|
-
case ' ':
|
|
74
|
-
case '\t':
|
|
75
|
-
case ' ':
|
|
76
|
-
return true;
|
|
77
|
-
case '\r':
|
|
78
|
-
case '\n':
|
|
79
|
-
return linebreak;
|
|
80
|
-
default:
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
71
|
|
|
85
|
-
function next(source: string, position: number, state: number): number {
|
|
86
|
-
let index= seek(source, position, state);
|
|
72
|
+
function next(source: string, position: number, space: boolean, state: number): number {
|
|
73
|
+
let index= seek(source, position, space, state);
|
|
87
74
|
assert(index > position);
|
|
88
75
|
if (index === source.length) return index;
|
|
89
76
|
const char = source[index];
|
|
90
77
|
switch (char) {
|
|
91
78
|
case '%':
|
|
92
|
-
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1]
|
|
79
|
+
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1]));
|
|
93
80
|
index += index - 1 > position
|
|
94
81
|
? -1
|
|
95
82
|
: 0;
|
|
@@ -167,7 +154,7 @@ export function isAlphanumeric(char: string): boolean {
|
|
|
167
154
|
return 'A' <= char && char <= 'Z';
|
|
168
155
|
}
|
|
169
156
|
|
|
170
|
-
function seek(source: string, position: number, state: number): number {
|
|
157
|
+
function seek(source: string, position: number, space: boolean, state: number): number {
|
|
171
158
|
for (let i = position + 1; i < source.length; ++i) {
|
|
172
159
|
const char = source[i];
|
|
173
160
|
switch (char) {
|
|
@@ -208,7 +195,7 @@ function seek(source: string, position: number, state: number): number {
|
|
|
208
195
|
if (source[i + 1] === char && source[i + 2] === char) return i;
|
|
209
196
|
continue;
|
|
210
197
|
case '%':
|
|
211
|
-
if (source[i + 1] === ']' && isWhitespace(source[i - 1]
|
|
198
|
+
if (source[i + 1] === ']' && isWhitespace(source[i - 1])) return i;
|
|
212
199
|
continue;
|
|
213
200
|
case ':':
|
|
214
201
|
if (source[i + 1] === '/' && source[i + 2] === '/') return i;
|
|
@@ -216,30 +203,14 @@ function seek(source: string, position: number, state: number): number {
|
|
|
216
203
|
case '&':
|
|
217
204
|
if (source[i + 1] !== ' ') return i;
|
|
218
205
|
continue;
|
|
219
|
-
case ' ':
|
|
220
|
-
case '\t':
|
|
221
|
-
case ' ':
|
|
222
|
-
if (i + 1 === source.length) return i;
|
|
223
|
-
switch (source[i + 1]) {
|
|
224
|
-
case ' ':
|
|
225
|
-
case '\t':
|
|
226
|
-
case '\r':
|
|
227
|
-
case '\n':
|
|
228
|
-
case ' ':
|
|
229
|
-
return i;
|
|
230
|
-
case '\\':
|
|
231
|
-
if (i + 2 === source.length) return i;
|
|
232
|
-
switch (source[i + 2]) {
|
|
233
|
-
case ' ':
|
|
234
|
-
case '\t':
|
|
235
|
-
case '\r':
|
|
236
|
-
case '\n':
|
|
237
|
-
case ' ':
|
|
238
|
-
return i;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
continue;
|
|
242
206
|
default:
|
|
207
|
+
if (!isWhitespace(char)) continue;
|
|
208
|
+
if (space) return i;
|
|
209
|
+
if (i + 1 === source.length) return i;
|
|
210
|
+
if (isWhitespace(source[i + 1])) return i;
|
|
211
|
+
if (source[i + 1] !== '\\') continue;
|
|
212
|
+
if (i + 2 === source.length) return i;
|
|
213
|
+
if (isWhitespace(source[i + 2])) return i;
|
|
243
214
|
continue;
|
|
244
215
|
}
|
|
245
216
|
assert(false);
|
|
@@ -24,7 +24,6 @@ export const unescsource: UnescapableSourceParser = (input, output) => {
|
|
|
24
24
|
return output.append(new Node(html('br'), Flag.blank));
|
|
25
25
|
default:
|
|
26
26
|
assert(char !== '\n');
|
|
27
|
-
if (input.sequential) return output.append(new Node(char));
|
|
28
27
|
nonWhitespace.lastIndex = position + 1;
|
|
29
28
|
let i = canSkip(source, position)
|
|
30
29
|
? nonWhitespace.test(source)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5Cp%7BWhite_Space%7D&g=&i=
|
|
2
|
+
// https://en.wikipedia.org/wiki/Whitespace_character
|
|
3
|
+
// https://en.wikipedia.org/wiki/Newline
|
|
4
|
+
export function isWhitespace(char: string, linebreak: boolean = true): boolean {
|
|
5
|
+
switch (char) {
|
|
6
|
+
case '\u0009':
|
|
7
|
+
case '\u000B':
|
|
8
|
+
case '\u000C':
|
|
9
|
+
case '\u0020':
|
|
10
|
+
case '\u0085':
|
|
11
|
+
case '\u00A0':
|
|
12
|
+
case '\u1680':
|
|
13
|
+
case '\u2000':
|
|
14
|
+
case '\u2001':
|
|
15
|
+
case '\u2002':
|
|
16
|
+
case '\u2003':
|
|
17
|
+
case '\u2004':
|
|
18
|
+
case '\u2005':
|
|
19
|
+
case '\u2006':
|
|
20
|
+
case '\u2007':
|
|
21
|
+
case '\u2008':
|
|
22
|
+
case '\u2009':
|
|
23
|
+
case '\u200A':
|
|
24
|
+
case '\u2028':
|
|
25
|
+
case '\u2029':
|
|
26
|
+
case '\u202F':
|
|
27
|
+
case '\u205F':
|
|
28
|
+
case '\u3000':
|
|
29
|
+
return true;
|
|
30
|
+
case '\u000A':
|
|
31
|
+
case '\u000D':
|
|
32
|
+
return linebreak;
|
|
33
|
+
default:
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/parser/source.ts
CHANGED
|
@@ -15,4 +15,5 @@ export { text, txt } from './source/text';
|
|
|
15
15
|
export { escsource } from './source/escapable';
|
|
16
16
|
export { unescsource } from './source/unescapable';
|
|
17
17
|
export { str, strs } from './source/str';
|
|
18
|
+
export { isWhitespace } from './source/whitespace';
|
|
18
19
|
export { contentline, emptyline, emptysegment, anyline } from './source/line';
|
package/src/parser/visibility.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Input, Command } from './context';
|
|
|
3
3
|
import { Flag } from './node';
|
|
4
4
|
import { always, fmap } from '../combinator';
|
|
5
5
|
import { invisibleBlankHTMLEntityNames } from '../api/normalize';
|
|
6
|
+
import { isWhitespace } from './source';
|
|
6
7
|
|
|
7
8
|
namespace blank {
|
|
8
9
|
export const line = new RegExp(
|
|
@@ -102,7 +103,7 @@ function isNonblank({ value: node, flags }: Node<HTMLElement | string>, strpos?:
|
|
|
102
103
|
case '\n':
|
|
103
104
|
return false;
|
|
104
105
|
default:
|
|
105
|
-
return str.trimStart()
|
|
106
|
+
return !isWhitespace(str.trimStart());
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|