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.
Files changed (34) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +100 -93
  3. package/package.json +1 -1
  4. package/src/combinator/control/constraint/line.ts +1 -1
  5. package/src/combinator/control/manipulation/match.ts +1 -1
  6. package/src/combinator/data/delimiter.ts +42 -37
  7. package/src/combinator/data/parser/context.ts +4 -2
  8. package/src/combinator/data/parser/inits.ts +1 -1
  9. package/src/combinator/data/parser/sequence.ts +1 -1
  10. package/src/combinator/data/parser/some.ts +4 -3
  11. package/src/parser/api/bind.ts +6 -8
  12. package/src/parser/api/header.ts +1 -1
  13. package/src/parser/api/parse.ts +5 -6
  14. package/src/parser/block/codeblock.ts +1 -1
  15. package/src/parser/block/extension/fig.ts +1 -1
  16. package/src/parser/block/extension/figure.ts +1 -1
  17. package/src/parser/block/extension/message.ts +1 -1
  18. package/src/parser/block/extension/placeholder.ts +1 -1
  19. package/src/parser/block/extension/table.ts +1 -1
  20. package/src/parser/block/heading.ts +1 -1
  21. package/src/parser/block/mathblock.ts +1 -1
  22. package/src/parser/block.ts +4 -5
  23. package/src/parser/header.test.ts +1 -0
  24. package/src/parser/header.ts +3 -3
  25. package/src/parser/inline/autolink.ts +3 -3
  26. package/src/parser/inline/bracket.ts +5 -6
  27. package/src/parser/inline/html.test.ts +5 -1
  28. package/src/parser/inline/html.ts +61 -53
  29. package/src/parser/inline.ts +7 -1
  30. package/src/parser/processor/note.ts +1 -1
  31. package/src/parser/segment.ts +7 -6
  32. package/src/parser/source/escapable.ts +0 -1
  33. package/src/parser/source/line.ts +6 -4
  34. 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, validate, surround, open, match, lazy } from '../../combinator';
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(() => validate(/<[a-z]+(?=[ >])/yi,
24
- union([
25
- surround(
26
- // https://html.spec.whatwg.org/multipage/syntax.html#void-elements
27
- str(/<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[ >])/y),
28
- precedence(9, some(union([attribute]))),
29
- open(str(/ ?/y), str('>'), true),
30
- true, [],
31
- ([as, bs = new List(), cs], context) =>
32
- 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)]),
33
- ([as, bs = new List()], context) =>
34
- new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
35
- match(
36
- new RegExp(String.raw`<(${TAGS.join('|')})(?=[ >])`, 'y'),
37
- memoize(
38
- ([, tag]) =>
39
- surround<HTMLParser.TagParser, string>(
40
- surround(
41
- str(`<${tag}`),
42
- precedence(9, some(attribute)),
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], context) =>
59
- new List([new Node(elem(tag, true, [...unwrap(as)], bs, cs, context))]),
60
- ([as, bs = new List()], context) =>
61
- new List([new Node(elem(tag, true, [...unwrap(as)], bs, new List(), context))])),
62
- ([, tag]) => tag,
63
- new Map())),
64
- surround(
65
- // https://html.spec.whatwg.org/multipage/syntax.html#void-elements
66
- str(/<[a-z]+(?=[ >])/yi),
67
- precedence(9, some(union([attribute]))),
68
- open(str(/ ?/y), str('>'), true),
69
- true, [],
70
- ([as, bs = new List(), cs], context) =>
71
- new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
72
- ([as, bs = new List()], context) =>
73
- new List([new Node(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
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(''));
@@ -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
+ }
@@ -226,7 +226,7 @@ function build(
226
226
  splitter.remove();
227
227
  }
228
228
  }
229
- }
229
+ };
230
230
  }
231
231
 
232
232
  function* proc(note: HTMLOListElement, defs?: Map<string, HTMLLIElement>): Generator<HTMLLIElement | undefined, undefined, undefined> {
@@ -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, context.segment]
57
- : yield [`${Command.Error}Too large segment over ${MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.\n${seg}`, Segment.unknown];
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 / 4
64
+ return source.length <= size / 2
64
65
  || source.length <= size && new Blob([source]).size <= size;
65
66
  }
@@ -31,7 +31,6 @@ export const escsource: EscapableSourceParser = context => {
31
31
  return new List([new Node(source.slice(position, position + 2))]);
32
32
  }
33
33
  case '\r':
34
- consume(-1, context);
35
34
  return new List();
36
35
  case '\n':
37
36
  context.linebreak ||= source.length - position;
@@ -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
- if (source[position] === '\n') return position + 1;
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
- if (source[position] === '\n') return;
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 fst = source[i];
182
- switch (fst) {
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] === fst) return i;
213
+ if (source[i + 1] === char) return i;
215
214
  continue;
216
215
  case '/':
217
- if (source[i + 1] === fst && source[i + 2] === fst) return i;
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;