securemark 0.293.3 → 0.293.5
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 +125 -141
- package/package.json +1 -1
- package/src/combinator/control/manipulation/surround.ts +2 -2
- package/src/combinator/data/parser/context.test.ts +10 -9
- package/src/combinator/data/parser/context.ts +2 -1
- package/src/combinator/data/parser.ts +0 -3
- package/src/parser/api/bind.ts +3 -3
- package/src/parser/api/normalize.ts +1 -3
- package/src/parser/api/parse.ts +1 -1
- package/src/parser/block/dlist.test.ts +1 -1
- package/src/parser/block/heading.test.ts +1 -0
- package/src/parser/block/olist.test.ts +1 -0
- package/src/parser/block/reply/quote.ts +6 -6
- package/src/parser/block/reply.ts +3 -2
- package/src/parser/block/ulist.test.ts +1 -0
- package/src/parser/header.test.ts +3 -1
- package/src/parser/header.ts +2 -2
- package/src/parser/inline/emphasis.test.ts +1 -0
- package/src/parser/inline/html.test.ts +3 -3
- package/src/parser/inline/html.ts +9 -9
- package/src/parser/inline/italic.test.ts +1 -0
- package/src/parser/inline/link.test.ts +10 -8
- package/src/parser/inline/link.ts +17 -17
- package/src/parser/inline/mark.test.ts +1 -0
- package/src/parser/inline/media.test.ts +6 -7
- package/src/parser/inline/media.ts +3 -3
- package/src/parser/inline/remark.test.ts +3 -1
- package/src/parser/inline/strong.test.ts +1 -0
- package/src/parser/source/escapable.test.ts +1 -0
- package/src/parser/source/escapable.ts +3 -11
- package/src/parser/source/text.test.ts +5 -4
- package/src/parser/source/text.ts +90 -94
- package/src/parser/source/unescapable.test.ts +1 -0
- package/src/parser/source/unescapable.ts +5 -8
- package/src/parser/util.ts +0 -19
|
@@ -15,6 +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('a b c'), ctx), [['a b c'], '']);
|
|
18
19
|
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09あいAZaz'], '']);
|
|
19
20
|
assert.deepStrictEqual(inspect(parser('a\nb'), ctx), [['a', '<br>', 'b'], '']);
|
|
20
21
|
});
|
|
@@ -39,8 +40,8 @@ describe('Unit: parser/source/text', () => {
|
|
|
39
40
|
assert.deepStrictEqual(inspect(parser(' '), ctx), [[], '']);
|
|
40
41
|
assert.deepStrictEqual(inspect(parser(' \n'), ctx), [['<br>'], '']);
|
|
41
42
|
assert.deepStrictEqual(inspect(parser(' \n'), ctx), [['<br>'], '']);
|
|
42
|
-
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
|
|
43
|
-
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [[' ', '<br>'], '']);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [[' ', ' ', '<br>'], '']);
|
|
44
45
|
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' a'], '']);
|
|
45
46
|
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
|
|
46
47
|
assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
|
|
@@ -48,8 +49,8 @@ describe('Unit: parser/source/text', () => {
|
|
|
48
49
|
assert.deepStrictEqual(inspect(parser('a '), ctx), [['a'], '']);
|
|
49
50
|
assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
|
|
50
51
|
assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
|
|
52
|
-
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
|
|
52
|
+
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', ' ', '<br>'], '']);
|
|
53
|
+
assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', ' ', '<br>'], '']);
|
|
53
54
|
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a b'], '']);
|
|
54
55
|
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
|
|
55
56
|
assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
|
|
@@ -4,7 +4,7 @@ import { union, consume, focus } from '../../combinator';
|
|
|
4
4
|
import { html } from 'typed-dom/dom';
|
|
5
5
|
|
|
6
6
|
//const delimiter = /(?=[\\!@#$&"`\[\](){}<>()[]{}*%|\r\n]|([+~=])\1|\/{3}|\s(?:\\?(?:$|\s)|[$%])|:\/\/)/g;
|
|
7
|
-
export const nonWhitespace = /[\
|
|
7
|
+
export const nonWhitespace = /[^ \t ]/g;
|
|
8
8
|
|
|
9
9
|
export const text: TextParser = input => {
|
|
10
10
|
const { context } = input;
|
|
@@ -38,29 +38,24 @@ export const text: TextParser = input => {
|
|
|
38
38
|
assert(char !== '\n');
|
|
39
39
|
if (context.sequential) return [[char]];
|
|
40
40
|
nonWhitespace.lastIndex = position + 1;
|
|
41
|
-
const
|
|
42
|
-
let i =
|
|
43
|
-
? source
|
|
44
|
-
?
|
|
45
|
-
:
|
|
46
|
-
? nonWhitespace.lastIndex - 1
|
|
47
|
-
: source.length
|
|
41
|
+
const s = canSkip(source, position);
|
|
42
|
+
let i = s
|
|
43
|
+
? nonWhitespace.test(source)
|
|
44
|
+
? nonWhitespace.lastIndex - 1
|
|
45
|
+
: source.length
|
|
48
46
|
: next(source, position);
|
|
49
47
|
assert(i > position);
|
|
50
48
|
const lineend = 0
|
|
51
|
-
||
|
|
52
|
-
||
|
|
53
|
-
|| b && source[i] === '\\' && source[i + 1] === '\n';
|
|
49
|
+
|| s && i === source.length
|
|
50
|
+
|| s && source[i] === '\n';
|
|
54
51
|
i -= position;
|
|
55
|
-
i = lineend ? i : i - +
|
|
52
|
+
i = lineend ? i : i - +s || 1;
|
|
56
53
|
consume(i - 1, context);
|
|
57
54
|
context.position += i - 1;
|
|
58
55
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
59
|
-
|
|
60
|
-
i += position;
|
|
61
|
-
return i === context.position || b && !linestart || lineend
|
|
56
|
+
return position === context.position || s && !linestart || lineend
|
|
62
57
|
? [[]]
|
|
63
|
-
: [[source.slice(
|
|
58
|
+
: [[source.slice(position, context.position)]];
|
|
64
59
|
}
|
|
65
60
|
};
|
|
66
61
|
|
|
@@ -72,6 +67,26 @@ export const linebreak: LinebreakParser = focus(/[\r\n]/y, union([
|
|
|
72
67
|
text,
|
|
73
68
|
])) as LinebreakParser;
|
|
74
69
|
|
|
70
|
+
export function canSkip(source: string, position: number): boolean {
|
|
71
|
+
assert(position < source.length);
|
|
72
|
+
if (!isWhitespace(source[position], false)) return false;
|
|
73
|
+
if (position + 1 === source.length) return true;
|
|
74
|
+
return isWhitespace(source[position + 1], true);
|
|
75
|
+
}
|
|
76
|
+
function isWhitespace(char: string, linebreak: boolean): boolean {
|
|
77
|
+
switch (char) {
|
|
78
|
+
case ' ':
|
|
79
|
+
case '\t':
|
|
80
|
+
case ' ':
|
|
81
|
+
return true;
|
|
82
|
+
case '\r':
|
|
83
|
+
case '\n':
|
|
84
|
+
return linebreak;
|
|
85
|
+
default:
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
export function next(source: string, position: number, delimiter?: RegExp): number {
|
|
76
91
|
let index: number;
|
|
77
92
|
if (delimiter) {
|
|
@@ -86,8 +101,24 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
|
|
|
86
101
|
assert(index > position);
|
|
87
102
|
const char = source[index];
|
|
88
103
|
switch (char) {
|
|
104
|
+
case '$':
|
|
105
|
+
case '%':
|
|
106
|
+
case '*':
|
|
107
|
+
case '+':
|
|
108
|
+
case '~':
|
|
109
|
+
case '=':
|
|
110
|
+
case '/':
|
|
111
|
+
index = backToWhitespace(source, position, index);
|
|
112
|
+
break;
|
|
113
|
+
case '[':
|
|
114
|
+
index = source[index + 1] === '|'
|
|
115
|
+
? backToWhitespace(source, position, index)
|
|
116
|
+
: index;
|
|
117
|
+
break;
|
|
89
118
|
case ':':
|
|
90
|
-
index =
|
|
119
|
+
index = source.startsWith('//', index + 1)
|
|
120
|
+
? backToUrlHead(source, position, index)
|
|
121
|
+
: index;
|
|
91
122
|
break;
|
|
92
123
|
case '@':
|
|
93
124
|
index = backToEmailHead(source, position, index);
|
|
@@ -96,39 +127,39 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
|
|
|
96
127
|
assert(index > position);
|
|
97
128
|
return index;
|
|
98
129
|
}
|
|
130
|
+
export function backToWhitespace(source: string, position: number, index: number): number {
|
|
131
|
+
const prev = index - 1;
|
|
132
|
+
return prev > position && /\s/.test(source[prev])
|
|
133
|
+
? prev
|
|
134
|
+
: index;
|
|
135
|
+
}
|
|
99
136
|
export function backToUrlHead(source: string, position: number, index: number): number {
|
|
100
137
|
const delim = index;
|
|
101
138
|
let state = false;
|
|
102
|
-
let
|
|
103
|
-
for (let i = index; --i > position;) {
|
|
104
|
-
index = i;
|
|
139
|
+
for (let i = index - 1; i >= position; --i) {
|
|
105
140
|
const char = source[i];
|
|
106
141
|
if (state) switch (char) {
|
|
107
142
|
case '.':
|
|
108
143
|
case '+':
|
|
109
144
|
case '-':
|
|
110
145
|
state = false;
|
|
111
|
-
offset = 1;
|
|
112
146
|
continue;
|
|
113
147
|
}
|
|
114
148
|
if (isAlphanumeric(char)) {
|
|
115
149
|
state = true;
|
|
116
|
-
|
|
150
|
+
index = i;
|
|
117
151
|
continue;
|
|
118
152
|
}
|
|
119
153
|
break;
|
|
120
154
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return index + offset;
|
|
155
|
+
return index === position
|
|
156
|
+
? delim
|
|
157
|
+
: index;
|
|
125
158
|
}
|
|
126
159
|
export function backToEmailHead(source: string, position: number, index: number): number {
|
|
127
160
|
const delim = index;
|
|
128
161
|
let state = false;
|
|
129
|
-
let
|
|
130
|
-
for (let i = index; --i > position;) {
|
|
131
|
-
index = i;
|
|
162
|
+
for (let i = index - 1; i >= position; --i) {
|
|
132
163
|
const char = source[i];
|
|
133
164
|
if (state) switch (char) {
|
|
134
165
|
case '_':
|
|
@@ -136,22 +167,19 @@ export function backToEmailHead(source: string, position: number, index: number)
|
|
|
136
167
|
case '+':
|
|
137
168
|
case '-':
|
|
138
169
|
state = false;
|
|
139
|
-
offset = 1;
|
|
140
170
|
continue;
|
|
141
171
|
}
|
|
142
172
|
if (isAlphanumeric(char)) {
|
|
143
173
|
state = true;
|
|
144
|
-
|
|
174
|
+
index = i;
|
|
145
175
|
continue;
|
|
146
176
|
}
|
|
147
177
|
break;
|
|
148
178
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return index + offset;
|
|
179
|
+
return index === position
|
|
180
|
+
? delim
|
|
181
|
+
: index;
|
|
153
182
|
}
|
|
154
|
-
|
|
155
183
|
function isAlphanumeric(char: string): boolean {
|
|
156
184
|
assert(char.length === 1);
|
|
157
185
|
if (char < '0' || '\x7F' < char) return false;
|
|
@@ -195,8 +223,6 @@ function isAlphanumeric(char: string): boolean {
|
|
|
195
223
|
// }
|
|
196
224
|
//};
|
|
197
225
|
|
|
198
|
-
const delimiter = /\s(?:\\?(?:$|\s)|[$%])/y;
|
|
199
|
-
|
|
200
226
|
function seek(source: string, position: number): number {
|
|
201
227
|
for (let i = position + 1; i < source.length; ++i) {
|
|
202
228
|
const fst = source[i];
|
|
@@ -225,7 +251,6 @@ function seek(source: string, position: number): number {
|
|
|
225
251
|
case '{':
|
|
226
252
|
case '}':
|
|
227
253
|
case '*':
|
|
228
|
-
case '%':
|
|
229
254
|
case '|':
|
|
230
255
|
case '\r':
|
|
231
256
|
case '\n':
|
|
@@ -238,68 +263,39 @@ function seek(source: string, position: number): number {
|
|
|
238
263
|
case '/':
|
|
239
264
|
if (source[i + 1] === fst && source[i + 2] === fst) return i;
|
|
240
265
|
continue;
|
|
266
|
+
case '%':
|
|
267
|
+
if (source[i + 1] === ']') return i;
|
|
268
|
+
continue;
|
|
241
269
|
case ':':
|
|
242
270
|
if (source[i + 1] === '/' && source[i + 2] === '/') return i;
|
|
243
271
|
continue;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// }
|
|
268
|
-
// continue;
|
|
272
|
+
case ' ':
|
|
273
|
+
case '\t':
|
|
274
|
+
case ' ':
|
|
275
|
+
if (i + 1 === source.length) return i;
|
|
276
|
+
switch (source[i + 1]) {
|
|
277
|
+
case ' ':
|
|
278
|
+
case '\t':
|
|
279
|
+
case '\r':
|
|
280
|
+
case '\n':
|
|
281
|
+
case ' ':
|
|
282
|
+
return i;
|
|
283
|
+
case '\\':
|
|
284
|
+
if (i + 2 === source.length) return i;
|
|
285
|
+
switch (source[i + 2]) {
|
|
286
|
+
case ' ':
|
|
287
|
+
case '\t':
|
|
288
|
+
case '\r':
|
|
289
|
+
case '\n':
|
|
290
|
+
case ' ':
|
|
291
|
+
return i;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
continue;
|
|
269
295
|
default:
|
|
270
|
-
delimiter.lastIndex = i;
|
|
271
|
-
if (delimiter.test(source)) return i;
|
|
272
296
|
continue;
|
|
273
297
|
}
|
|
274
298
|
assert(false);
|
|
275
299
|
}
|
|
276
300
|
return source.length;
|
|
277
301
|
}
|
|
278
|
-
|
|
279
|
-
const blank = /\s(?:$|\s|\\\n)/y;
|
|
280
|
-
export function isBlank(source: string, position: number): boolean {
|
|
281
|
-
blank.lastIndex = position;
|
|
282
|
-
return blank.test(source);
|
|
283
|
-
assert(position < source.length);
|
|
284
|
-
if (!isWhitespace(source[position])) return false;
|
|
285
|
-
if (position + 1 === source.length) return true;
|
|
286
|
-
const snd = source[position + 1];
|
|
287
|
-
if (isWhitespace(snd)) return true;
|
|
288
|
-
if (position + 2 === source.length) return false;
|
|
289
|
-
if (snd === '\\' && source[position + 2] === '\n') return true;
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
const whitespace = /\s/;
|
|
293
|
-
export function isWhitespace(char: string): boolean {
|
|
294
|
-
whitespace;
|
|
295
|
-
switch (char) {
|
|
296
|
-
case ' ':
|
|
297
|
-
case '\t':
|
|
298
|
-
case '\r':
|
|
299
|
-
case '\n':
|
|
300
|
-
case ' ':
|
|
301
|
-
return true
|
|
302
|
-
default:
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
@@ -15,6 +15,7 @@ describe('Unit: parser/source/unescapable', () => {
|
|
|
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('a b c'), ctx), [['a', ' b', ' c'], '']);
|
|
18
19
|
assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09', 'あいAZaz'], '']);
|
|
19
20
|
});
|
|
20
21
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UnescapableSourceParser } from '../source';
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { consume } from '../../combinator';
|
|
4
|
-
import { nonWhitespace,
|
|
4
|
+
import { nonWhitespace, canSkip, next } from './text';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
|
|
@@ -28,13 +28,10 @@ export const unescsource: UnescapableSourceParser = ({ context }) => {
|
|
|
28
28
|
assert(char !== '\n');
|
|
29
29
|
if (context.sequential) return [[char]];
|
|
30
30
|
nonWhitespace.lastIndex = position + 1;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: nonWhitespace.test(source)
|
|
36
|
-
? nonWhitespace.lastIndex - 1
|
|
37
|
-
: source.length
|
|
31
|
+
let i = canSkip(source, position)
|
|
32
|
+
? nonWhitespace.test(source)
|
|
33
|
+
? nonWhitespace.lastIndex - 1
|
|
34
|
+
: source.length
|
|
38
35
|
: next(source, position, delimiter);
|
|
39
36
|
assert(i > position);
|
|
40
37
|
i -= position;
|
package/src/parser/util.ts
CHANGED
|
@@ -2,27 +2,8 @@ import { min } from 'spica/alias';
|
|
|
2
2
|
import { MarkdownParser } from '../../markdown';
|
|
3
3
|
import { Command } from './context';
|
|
4
4
|
import { Parser, Result, Ctx, Node, Context, eval, failsafe } from '../combinator/data/parser';
|
|
5
|
-
import { convert } from '../combinator';
|
|
6
5
|
import { define } from 'typed-dom/dom';
|
|
7
6
|
|
|
8
|
-
export function linearize<P extends Parser<HTMLElement | string>>(parser: P, trim?: 0 | 1 | -1): P;
|
|
9
|
-
export function linearize<N extends HTMLElement | string>(parser: Parser<N>, trim = 0): Parser<N> {
|
|
10
|
-
return convert(
|
|
11
|
-
source => `${
|
|
12
|
-
trim === 0
|
|
13
|
-
? source
|
|
14
|
-
: trim > 0
|
|
15
|
-
? source.at(-1) === '\n'
|
|
16
|
-
? source
|
|
17
|
-
: source + '\n'
|
|
18
|
-
: source.at(-1) === '\n'
|
|
19
|
-
? source.slice(0, -1)
|
|
20
|
-
: source
|
|
21
|
-
}`,
|
|
22
|
-
parser,
|
|
23
|
-
trim === 0);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
7
|
export function repeat<P extends Parser<HTMLElement | string, MarkdownParser.Context>>(symbol: string, parser: P, cons: (nodes: Node<P>[], context: Context<P>) => Node<P>[], termination?: (acc: Node<P>[], context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | Node<P>>): P;
|
|
27
8
|
export function repeat<N extends HTMLElement | string>(symbol: string, parser: Parser<N>, cons: (nodes: N[], context: MarkdownParser.Context) => N[], termination: (acc: N[], context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | N, MarkdownParser.Context> = (nodes, context, prefix, postfix) => {
|
|
28
9
|
const acc = [];
|