securemark 0.298.2 → 0.298.3
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 +100 -93
- package/package.json +1 -1
- package/src/combinator/control/constraint/line.ts +1 -1
- package/src/combinator/control/manipulation/match.ts +1 -1
- package/src/combinator/data/delimiter.ts +42 -37
- package/src/combinator/data/parser/context.ts +4 -2
- package/src/combinator/data/parser/inits.ts +1 -1
- package/src/combinator/data/parser/sequence.ts +1 -1
- package/src/combinator/data/parser/some.ts +4 -3
- package/src/parser/api/bind.ts +6 -8
- package/src/parser/api/header.ts +1 -1
- package/src/parser/api/parse.ts +5 -6
- package/src/parser/block/codeblock.ts +1 -1
- package/src/parser/block/extension/fig.ts +1 -1
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/placeholder.ts +1 -1
- package/src/parser/block/extension/table.ts +1 -1
- package/src/parser/block/heading.ts +1 -1
- package/src/parser/block/mathblock.ts +1 -1
- package/src/parser/block.ts +4 -5
- package/src/parser/header.test.ts +1 -0
- package/src/parser/header.ts +3 -3
- package/src/parser/inline/autolink.ts +3 -3
- package/src/parser/inline/bracket.ts +5 -6
- package/src/parser/inline/html.test.ts +5 -1
- package/src/parser/inline/html.ts +61 -53
- package/src/parser/inline.ts +7 -1
- package/src/parser/processor/note.ts +1 -1
- package/src/parser/segment.ts +7 -6
- package/src/parser/source/escapable.ts +0 -1
- package/src/parser/source/line.ts +6 -4
- package/src/parser/source/text.ts +4 -5
|
@@ -2,7 +2,7 @@ import { HTMLParser } from '../inline';
|
|
|
2
2
|
import { Recursion } from '../context';
|
|
3
3
|
import { List, Node, Context } from '../../combinator/data/parser';
|
|
4
4
|
import { Flag } from '../node';
|
|
5
|
-
import { union, some, recursion, precedence,
|
|
5
|
+
import { union, some, recursion, precedence, surround, open, match, lazy } from '../../combinator';
|
|
6
6
|
import { inline } from '../inline';
|
|
7
7
|
import { str } from '../source';
|
|
8
8
|
import { isNonblankFirstLine, blankWith } from '../visibility';
|
|
@@ -20,58 +20,57 @@ const attrspecs = {
|
|
|
20
20
|
Object.setPrototypeOf(attrspecs, null);
|
|
21
21
|
Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
|
|
22
22
|
|
|
23
|
-
export const html: HTMLParser = lazy(() =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
([as, bs
|
|
32
|
-
|
|
33
|
-
([as, bs
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
surround
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
open(str(/ ?/y), str('>'), true),
|
|
44
|
-
true, [],
|
|
45
|
-
([as, bs = new List(), cs]) => as.import(bs).import(cs),
|
|
46
|
-
([as, bs = new List()]) => as.import(bs)),
|
|
47
|
-
// 不可視のHTML構造が可視構造を変化させるべきでない。
|
|
48
|
-
// 可視のHTMLは優先度変更を検討する。
|
|
49
|
-
// このため`<>`記号は将来的に共通構造を変化させる可能性があり
|
|
50
|
-
// 共通構造を変化させない非構造文字列としては依然としてエスケープを要する。
|
|
51
|
-
precedence(0, recursion(Recursion.inline,
|
|
52
|
-
some(union([
|
|
53
|
-
some(inline, blankWith('\n', `</${tag}>`)),
|
|
54
|
-
open('\n', some(inline, `</${tag}>`), true),
|
|
55
|
-
])))),
|
|
56
|
-
str(`</${tag}>`),
|
|
23
|
+
export const html: HTMLParser = lazy(() => union([
|
|
24
|
+
surround(
|
|
25
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
26
|
+
str(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/y),
|
|
27
|
+
precedence(9, some(union([attribute]))),
|
|
28
|
+
open(str(/ ?/y), str('>'), true),
|
|
29
|
+
true, [],
|
|
30
|
+
([as, bs = new List(), cs], context) =>
|
|
31
|
+
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context), as.head!.value === '<wbr' ? Flag.blank : Flag.none)]),
|
|
32
|
+
([as, bs = new List()], context) =>
|
|
33
|
+
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
|
|
34
|
+
match(
|
|
35
|
+
new RegExp(String.raw`<(${TAGS.join('|')})(?=[ >])`, 'y'),
|
|
36
|
+
memoize(
|
|
37
|
+
([, tag]) =>
|
|
38
|
+
surround<HTMLParser.TagParser, string>(
|
|
39
|
+
surround(
|
|
40
|
+
str(`<${tag}`),
|
|
41
|
+
precedence(9, some(attribute)),
|
|
42
|
+
open(str(/ ?/y), str('>'), true),
|
|
57
43
|
true, [],
|
|
58
|
-
([as, bs = new List(), cs]
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
44
|
+
([as, bs = new List(), cs]) => as.import(bs).import(cs),
|
|
45
|
+
([as, bs = new List()]) => as.import(bs)),
|
|
46
|
+
// 不可視のHTML構造が可視構造を変化させるべきでない。
|
|
47
|
+
// 可視のHTMLは優先度変更を検討する。
|
|
48
|
+
// このため`<>`記号は将来的に共通構造を変化させる可能性があり
|
|
49
|
+
// 共通構造を変化させない非構造文字列としては依然としてエスケープを要する。
|
|
50
|
+
precedence(0, recursion(Recursion.inline,
|
|
51
|
+
some(union([
|
|
52
|
+
some(inline, blankWith('\n', `</${tag}>`)),
|
|
53
|
+
open('\n', some(inline, `</${tag}>`), true),
|
|
54
|
+
])))),
|
|
55
|
+
str(`</${tag}>`),
|
|
56
|
+
true, [],
|
|
57
|
+
([as, bs = new List(), cs], context) =>
|
|
58
|
+
new List([new Node(elem(tag, true, [...unwrap(as)], bs, cs, context))]),
|
|
59
|
+
([as, bs = new List()], context) =>
|
|
60
|
+
new List([new Node(elem(tag, true, [...unwrap(as)], bs, new List(), context))])),
|
|
61
|
+
([, tag]) => tag2index(tag),
|
|
62
|
+
Array(TAGS.length))),
|
|
63
|
+
surround(
|
|
64
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
65
|
+
str(/<[a-z]+(?=[ >])/yi),
|
|
66
|
+
precedence(9, some(union([attribute]))),
|
|
67
|
+
open(str(/ ?/y), str('>'), true),
|
|
68
|
+
true, [],
|
|
69
|
+
([as, bs = new List(), cs], context) =>
|
|
70
|
+
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
|
|
71
|
+
([as, bs = new List()], context) =>
|
|
72
|
+
new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
|
|
73
|
+
]));
|
|
75
74
|
|
|
76
75
|
export const attribute: HTMLParser.AttributeParser = union([
|
|
77
76
|
str(/ [a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[ >])/yi),
|
|
@@ -146,7 +145,7 @@ export function attributes(
|
|
|
146
145
|
|
|
147
146
|
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
|
148
147
|
// [...document.querySelectorAll('tbody > tr > td:first-child')].map(el => el.textContent.slice(1, -1))
|
|
149
|
-
const TAGS: readonly string[] = [
|
|
148
|
+
export const TAGS: readonly string[] = [
|
|
150
149
|
"html",
|
|
151
150
|
"base",
|
|
152
151
|
"head",
|
|
@@ -284,3 +283,12 @@ const TAGS: readonly string[] = [
|
|
|
284
283
|
"tt",
|
|
285
284
|
"xmp",
|
|
286
285
|
];
|
|
286
|
+
|
|
287
|
+
const tag2index: (tag: string) => number = eval([
|
|
288
|
+
'tag => {',
|
|
289
|
+
'switch(tag){',
|
|
290
|
+
TAGS.map((tag, i) => `case '${tag}':return ${i};`).join(''),
|
|
291
|
+
'default: throw new Error();',
|
|
292
|
+
'}',
|
|
293
|
+
'}',
|
|
294
|
+
].join(''));
|
package/src/parser/inline.ts
CHANGED
|
@@ -92,7 +92,8 @@ export const inline: InlineParser = lazy(() => union([
|
|
|
92
92
|
case '{':
|
|
93
93
|
return bracket(input);
|
|
94
94
|
case '<':
|
|
95
|
-
return html(input);
|
|
95
|
+
if (isAlphabet(source[position + 1])) return html(input);
|
|
96
|
+
break;
|
|
96
97
|
case '$':
|
|
97
98
|
if (source[position + 1] === '{') return math(input);
|
|
98
99
|
return label(input)
|
|
@@ -131,3 +132,8 @@ export { dataindex } from './inline/extension/index';
|
|
|
131
132
|
export { medialink } from './inline/link';
|
|
132
133
|
export { media } from './inline/media';
|
|
133
134
|
export { shortmedia, lineshortmedia } from './inline/shortmedia';
|
|
135
|
+
|
|
136
|
+
function isAlphabet(char: string): boolean {
|
|
137
|
+
assert(char.length === 1);
|
|
138
|
+
return 'a' <= char && char <= 'z';
|
|
139
|
+
}
|
package/src/parser/segment.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { segment as codeblock } from './block/codeblock';
|
|
|
6
6
|
import { segment as mathblock } from './block/mathblock';
|
|
7
7
|
import { segment as extension } from './block/extension';
|
|
8
8
|
import { contentline, emptysegment } from './source';
|
|
9
|
+
import { normalize } from './api';
|
|
9
10
|
|
|
10
11
|
import SegmentParser = MarkdownParser.SegmentParser;
|
|
11
12
|
|
|
@@ -37,8 +38,8 @@ const parser: SegmentParser = union([
|
|
|
37
38
|
some(contentline, MAX_SEGMENT_SIZE + 1),
|
|
38
39
|
]);
|
|
39
40
|
|
|
40
|
-
export function* segment(source: string): Generator<readonly [string, Segment], undefined, undefined> {
|
|
41
|
-
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)}`, Segment.unknown];
|
|
41
|
+
export function* segment(source: string, initial = true): Generator<readonly [string, Segment], undefined, undefined> {
|
|
42
|
+
if (initial && !validate(source, MAX_INPUT_SIZE)) return yield [`${Command.Error}Too large input over ${MAX_INPUT_SIZE.toLocaleString('en')} bytes.\n${source.slice(0, 1001)}`, Segment.unknown];
|
|
42
43
|
assert(source.length < Number.MAX_SAFE_INTEGER);
|
|
43
44
|
for (let position = 0; position < source.length;) {
|
|
44
45
|
const context = new Context({ source, position });
|
|
@@ -52,14 +53,14 @@ export function* segment(source: string): Generator<readonly [string, Segment],
|
|
|
52
53
|
position = context.position;
|
|
53
54
|
for (let i = 0; i < segs.length; ++i) {
|
|
54
55
|
const seg = segs[i];
|
|
55
|
-
validate(seg, MAX_SEGMENT_SIZE)
|
|
56
|
-
? yield [seg
|
|
57
|
-
: yield [
|
|
56
|
+
initial && !validate(seg, MAX_SEGMENT_SIZE)
|
|
57
|
+
? yield [`${Command.Error}Too large segment over ${MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.\n${seg}`, Segment.unknown]
|
|
58
|
+
: yield [initial ? normalize(seg) : seg, context.segment];
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
export function validate(source: string, size: number): boolean {
|
|
63
|
-
return source.length <= size /
|
|
64
|
+
return source.length <= size / 2
|
|
64
65
|
|| source.length <= size && new Blob([source]).size <= size;
|
|
65
66
|
}
|
|
@@ -10,7 +10,7 @@ export const anyline: AnyLineParser = input => {
|
|
|
10
10
|
return new List();
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
const regEmptyline = /[^\S\n]*(?:$|\n)/y;
|
|
13
|
+
const regEmptyline = /[^\S\r\n]*(?:$|\r?\n)/y;
|
|
14
14
|
export const emptyline: EmptyLineParser = input => {
|
|
15
15
|
const context = input;
|
|
16
16
|
const { source, position } = context;
|
|
@@ -36,18 +36,20 @@ export const emptysegment: EmptySegmentParser = input => {
|
|
|
36
36
|
return new List();
|
|
37
37
|
};
|
|
38
38
|
function eoel(source: string, position: number): number {
|
|
39
|
-
|
|
39
|
+
const char = source[position];
|
|
40
|
+
if (char === '\n' || char === '\r' && source[position + 1] === '\n') return position + 1;
|
|
40
41
|
regEmptyline.lastIndex = position;
|
|
41
42
|
regEmptyline.test(source);
|
|
42
43
|
return regEmptyline.lastIndex || position;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
const regContentline = /[^\S\n]*\S[^\n]*(?:$|\n)/y;
|
|
46
|
+
const regContentline = /[^\S\r\n]*\S[^\r\n]*(?:$|\r?\n)/y;
|
|
46
47
|
export const contentline: ContentLineParser = input => {
|
|
47
48
|
const context = input;
|
|
48
49
|
const { source, position } = context;
|
|
49
50
|
if (position === source.length) return;
|
|
50
|
-
|
|
51
|
+
const char = source[position];
|
|
52
|
+
if (char === '\n' || char === '\r' && source[position + 1] === '\n') return;
|
|
51
53
|
regContentline.lastIndex = position;
|
|
52
54
|
regContentline.test(source);
|
|
53
55
|
const i = regContentline.lastIndex;
|
|
@@ -29,7 +29,6 @@ export const text: TextParser = input => {
|
|
|
29
29
|
return new List([new Node(source.slice(position + 1, context.position))]);
|
|
30
30
|
}
|
|
31
31
|
case '\r':
|
|
32
|
-
consume(-1, context);
|
|
33
32
|
return new List();
|
|
34
33
|
case '\n':
|
|
35
34
|
context.linebreak ||= source.length - position;
|
|
@@ -178,8 +177,8 @@ export function isAlphanumeric(char: string): boolean {
|
|
|
178
177
|
|
|
179
178
|
function seek(source: string, position: number, state: number): number {
|
|
180
179
|
for (let i = position + 1; i < source.length; ++i) {
|
|
181
|
-
const
|
|
182
|
-
switch (
|
|
180
|
+
const char = source[i];
|
|
181
|
+
switch (char) {
|
|
183
182
|
case '\\':
|
|
184
183
|
case '!':
|
|
185
184
|
case '$':
|
|
@@ -211,10 +210,10 @@ function seek(source: string, position: number, state: number): number {
|
|
|
211
210
|
case '+':
|
|
212
211
|
case '~':
|
|
213
212
|
case '=':
|
|
214
|
-
if (source[i + 1] ===
|
|
213
|
+
if (source[i + 1] === char) return i;
|
|
215
214
|
continue;
|
|
216
215
|
case '/':
|
|
217
|
-
if (source[i + 1] ===
|
|
216
|
+
if (source[i + 1] === char && source[i + 2] === char) return i;
|
|
218
217
|
continue;
|
|
219
218
|
case '%':
|
|
220
219
|
if (source[i + 1] === ']' && isWhitespace(source[i - 1], true)) return i;
|