securemark 0.283.1 → 0.283.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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +88 -50
  3. package/package.json +1 -1
  4. package/src/combinator/control/manipulation/indent.ts +1 -1
  5. package/src/combinator/data/parser/context/delimiter.ts +28 -3
  6. package/src/combinator/data/parser/context.ts +5 -2
  7. package/src/parser/block/dlist.ts +1 -1
  8. package/src/parser/context.ts +6 -6
  9. package/src/parser/inline/annotation.ts +2 -2
  10. package/src/parser/inline/autolink/url.ts +2 -2
  11. package/src/parser/inline/autolink.ts +1 -1
  12. package/src/parser/inline/bracket.ts +17 -14
  13. package/src/parser/inline/code.ts +1 -1
  14. package/src/parser/inline/deletion.ts +1 -1
  15. package/src/parser/inline/emphasis.test.ts +2 -2
  16. package/src/parser/inline/emphasis.ts +3 -3
  17. package/src/parser/inline/emstrong.ts +7 -7
  18. package/src/parser/inline/extension/index.ts +3 -3
  19. package/src/parser/inline/extension/indexee.ts +4 -2
  20. package/src/parser/inline/extension/placeholder.ts +2 -2
  21. package/src/parser/inline/html.ts +4 -4
  22. package/src/parser/inline/htmlentity.ts +5 -5
  23. package/src/parser/inline/insertion.ts +1 -1
  24. package/src/parser/inline/link.ts +4 -4
  25. package/src/parser/inline/mark.test.ts +2 -2
  26. package/src/parser/inline/mark.ts +3 -3
  27. package/src/parser/inline/math.ts +2 -2
  28. package/src/parser/inline/media.ts +2 -2
  29. package/src/parser/inline/reference.ts +2 -2
  30. package/src/parser/inline/remark.ts +2 -2
  31. package/src/parser/inline/ruby.ts +2 -2
  32. package/src/parser/inline/strong.test.ts +2 -2
  33. package/src/parser/inline/strong.ts +3 -3
  34. package/src/parser/inline/template.ts +2 -2
  35. package/src/parser/inline.test.ts +4 -2
  36. package/src/parser/visibility.ts +4 -4
@@ -33,7 +33,7 @@ const desc: DListParser.DescriptionParser = block(fmap(open(
33
33
  false);
34
34
 
35
35
  function fillTrailingDescription(es: HTMLElement[]): HTMLElement[] {
36
- return es.length > 0 && es[es.length - 1].tagName === 'DT'
36
+ return es.length > 0 && es.at(-1)!.tagName === 'DT'
37
37
  ? push(es, [html('dd')])
38
38
  : es;
39
39
  }
@@ -31,11 +31,11 @@ export const enum Recursion {
31
31
  }
32
32
 
33
33
  export const enum Backtrack {
34
- template = 1 << 8,
35
- media = 1 << 7,
36
- ruby = 1 << 6,
37
- link = 1 << 5,
38
- index = 1 << 4,
39
- url = 1 << 3,
34
+ template = 7 << 2,
35
+ index = 6 << 2,
36
+ ruby = 5 << 2,
37
+ link = 4 << 2,
38
+ media = 3 << 2,
39
+ url = 2 << 2,
40
40
  bracket = 1 << 2,
41
41
  }
@@ -8,8 +8,8 @@ import { html, defrag } from 'typed-dom/dom';
8
8
  export const annotation: AnnotationParser = lazy(() => creation(1, Recursion.ignore, surround(
9
9
  '((',
10
10
  constraint(State.annotation, false,
11
- syntax(6, State.annotation | State.media,
12
- trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 2]])))),
11
+ syntax(1, State.annotation | State.media,
12
+ trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 1]])))),
13
13
  '))',
14
14
  false,
15
15
  ([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest],
@@ -25,9 +25,9 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
25
25
  unsafelink)),
26
26
  ])));
27
27
 
28
- const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, precedence(2, union([
28
+ const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, precedence(1, union([
29
29
  surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.url),
30
30
  surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.url),
31
31
  surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.url),
32
- surround(str('"'), precedence(3, some(unescsource, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.url),
32
+ surround(str('"'), precedence(2, some(unescsource, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.url),
33
33
  ]))));
@@ -14,7 +14,7 @@ import { stringify } from '../util';
14
14
  export const autolink: AutolinkParser = lazy(() =>
15
15
  validate(/^(?:[@#>0-9a-z]|\S[#>]|[\r\n]!?https?:\/\/)/iu,
16
16
  constraint(State.autolink, false,
17
- syntax(1, ~State.shortcut,
17
+ syntax(0, ~State.shortcut,
18
18
  union([
19
19
  some(union([lineurl])),
20
20
  fmap(some(union([
@@ -6,42 +6,45 @@ import { State, Recursion, Backtrack } from '../context';
6
6
  import { unshift, push } from 'spica/array';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
- const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
9
+ const indexA = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
10
+ const indexF = new RegExp(indexA.source.replace(', ', '[,、]')
11
+ .replace(/[09AZaz.]|\-(?!\w)/g, c => String.fromCodePoint(c.codePointAt(0)! + 0xFEE0)));
10
12
 
11
13
  export const bracket: BracketParser = lazy(() => union([
12
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, str(index))), str(')')),
13
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[')', 2]]))), str(')'), true,
14
+ surround(str('('), creation(0, Recursion.bracket, syntax(1, State.none, str(indexA))), str(')')),
15
+ surround(str('('), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, ')', [[')', 1]]))), str(')'), true,
14
16
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
15
17
  ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
16
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, str(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))))), str(')')),
17
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[')', 2]]))), str(')'), true,
18
+ surround(str('('), creation(0, Recursion.bracket, syntax(1, State.none, str(indexF))), str(')')),
19
+ surround(str('('), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, ')', [[')', 1]]))), str(')'), true,
18
20
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
19
21
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
20
- surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[']', 2]]))), str(']'), true,
22
+ surround(str('['), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, ']', [[']', 1]]))), str(']'), true,
21
23
  undefined,
22
24
  ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
23
- surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[']', 2]]))), str(']'), true,
25
+ surround(str('['), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, ']', [[']', 1]]))), str(']'), true,
24
26
  undefined,
25
27
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
26
- surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [['}', 2]]))), str('}'), true,
28
+ surround(str('{'), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, '}', [['}', 1]]))), str('}'), true,
27
29
  undefined,
28
30
  ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
29
- surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [['}', 2]]))), str('}'), true,
31
+ surround(str('{'), creation(0, Recursion.bracket, syntax(1, State.none, some(inline, '}', [['}', 1]]))), str('}'), true,
30
32
  undefined,
31
33
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
32
- surround(str('"'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '"', [[/^\\?\n/, 9], ['"', 3]]))), str('"'), true,
34
+ // 改行禁止はバックトラックなしでは内側の構文を破壊するため安易に行えない。
35
+ surround(str('"'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '"', [[/^\\?\n/, 9], ['"', 2]]))), str('"'), true,
33
36
  undefined,
34
37
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
35
- surround(str('“'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '”', [[/^\\?\n/, 9], ['”', 3]]))), str('”'), true,
38
+ surround(str('“'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '”', [[/^\\?\n/, 9], ['”', 2]]))), str('”'), true,
36
39
  undefined,
37
40
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
38
- surround(str('‘'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '’', [[/^\\?\n/, 9], ['’', 3]]))), str('’'), true,
41
+ surround(str('‘'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '’', [[/^\\?\n/, 9], ['’', 2]]))), str('’'), true,
39
42
  undefined,
40
43
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
41
- surround(str('「'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '」', [[/^\\?\n/, 9], ['」', 3]]))), str('」'), true,
44
+ surround(str('「'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '」', [[/^\\?\n/, 9], ['」', 2]]))), str('」'), true,
42
45
  undefined,
43
46
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
44
- surround(str('『'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '』', [[/^\\?\n/, 9], ['』', 3]]))), str('』'), true,
47
+ surround(str('『'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '』', [[/^\\?\n/, 9], ['』', 2]]))), str('』'), true,
45
48
  undefined,
46
49
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
47
50
  ]));
@@ -10,7 +10,7 @@ export const code: CodeParser = creation(1, Recursion.ignore, validate('`', matc
10
10
 
11
11
  function format(text: string): string {
12
12
  assert(text.length > 0);
13
- return `${text[0]}${text[text.length - 1]}` === ' '
13
+ return `${text[0]}${text.at(-1)}` === ' '
14
14
  && text.trimStart()
15
15
  ? text.slice(1, -1)
16
16
  : text;
@@ -9,7 +9,7 @@ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const deletion: DeletionParser = lazy(() => creation(1, Recursion.inline, surround(
11
11
  str('~~', '~'),
12
- syntax(1, State.none,
12
+ syntax(0, State.none,
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '~~')),
15
15
  open('\n', some(inline, '~'), true),
@@ -12,10 +12,8 @@ describe('Unit: parser/inline/emphasis', () => {
12
12
  assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a'], ' *']);
13
13
  assert.deepStrictEqual(inspect(parser('*a *')), [['*', 'a', ' '], ' *']);
14
14
  assert.deepStrictEqual(inspect(parser('*a\n*')), [['*', 'a'], '\n*']);
15
- assert.deepStrictEqual(inspect(parser('*a\nb*')), [['*', 'a'], '\nb*']);
16
15
  assert.deepStrictEqual(inspect(parser('*a\\ *')), [['*', 'a'], '\\ *']);
17
16
  assert.deepStrictEqual(inspect(parser('*a\\\n*')), [['*', 'a'], '\\\n*']);
18
- assert.deepStrictEqual(inspect(parser('*a\\\nb*')), [['*', 'a'], '\\\nb*']);
19
17
  assert.deepStrictEqual(inspect(parser('*a**b')), [['*', 'a', '**', 'b'], '']);
20
18
  assert.deepStrictEqual(inspect(parser('*a**b*')), [['*', 'a', '**', 'b', '*'], '']);
21
19
  assert.deepStrictEqual(inspect(parser('* *')), undefined);
@@ -35,6 +33,8 @@ describe('Unit: parser/inline/emphasis', () => {
35
33
  assert.deepStrictEqual(inspect(parser('*a*')), [['<em>a</em>'], '']);
36
34
  assert.deepStrictEqual(inspect(parser('*ab*')), [['<em>ab</em>'], '']);
37
35
  assert.deepStrictEqual(inspect(parser('*a**')), [['<em>a</em>'], '*']);
36
+ assert.deepStrictEqual(inspect(parser('*a\nb*')), [['<em>a<br>b</em>'], '']);
37
+ assert.deepStrictEqual(inspect(parser('*a\\\nb*')), [['<em>a<br>b</em>'], '']);
38
38
  });
39
39
 
40
40
  it('nest', () => {
@@ -11,11 +11,11 @@ import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const emphasis: EmphasisParser = lazy(() => creation(1, Recursion.inline, surround(
13
13
  str('*', '*'),
14
- syntax(1, State.none,
14
+ syntax(0, State.none,
15
15
  startTight(some(union([
16
16
  strong,
17
- some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
18
- open(some(inline, '*', [[/^\\?\n/, 9]]), union([
17
+ some(inline, blankWith('*')),
18
+ open(some(inline, '*'), union([
19
19
  emstrong,
20
20
  strong,
21
21
  emphasis,
@@ -11,16 +11,16 @@ import { html, defrag } from 'typed-dom/dom';
11
11
  import { unshift } from 'spica/array';
12
12
 
13
13
  const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
14
- some(inline, blankWith('**'), [[/^\\?\n/, 9]]),
15
- open(some(inline, '*', [[/^\\?\n/, 9]]), union([
14
+ some(inline, blankWith('**')),
15
+ open(some(inline, '*'), union([
16
16
  emstrong,
17
17
  strong,
18
18
  ])),
19
19
  ])));
20
20
  const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
21
21
  strong,
22
- some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
23
- open(some(inline, '*', [[/^\\?\n/, 9]]), union([
22
+ some(inline, blankWith('*')),
23
+ open(some(inline, '*'), union([
24
24
  emstrong,
25
25
  strong,
26
26
  emphasis,
@@ -29,10 +29,10 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
29
29
 
30
30
  export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, surround(
31
31
  str('***'),
32
- syntax(1, State.none,
32
+ syntax(0, State.none,
33
33
  startTight(some(union([
34
- some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
35
- open(some(inline, '*', [[/^\\?\n/, 9]]), inline),
34
+ some(inline, blankWith('*')),
35
+ open(some(inline, '*'), inline),
36
36
  ])))),
37
37
  str(/^\*{1,3}/), false,
38
38
  ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
@@ -12,12 +12,12 @@ import IndexParser = ExtensionParser.IndexParser;
12
12
  export const index: IndexParser = lazy(() => validate('[#', creation(1, Recursion.ignore, fmap(indexee(surround(
13
13
  '[#',
14
14
  constraint(State.index, false,
15
- syntax(2, State.linkers | State.media,
15
+ syntax(1, State.linkers | State.media,
16
16
  startTight(
17
17
  some(inits([
18
18
  inline,
19
19
  signature,
20
- ]), ']', [[/^\\?\n/, 9], [']', 2]])))),
20
+ ]), ']', [[/^\\?\n/, 9], [']', 1]])))),
21
21
  ']',
22
22
  false,
23
23
  ([, ns], rest) => [[html('a', { 'data-index': dataindex(ns) }, trimNodeEnd(defrag(ns)))], rest],
@@ -42,7 +42,7 @@ const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(0
42
42
  surround(str('('), some(union([bracket, txt]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.index),
43
43
  surround(str('['), some(union([bracket, txt]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.index),
44
44
  surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.index),
45
- surround(str('"'), precedence(3, some(txt, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.index),
45
+ surround(str('"'), precedence(2, some(txt, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.index),
46
46
  ])));
47
47
 
48
48
  export function dataindex(ns: readonly (string | HTMLElement)[]): string | undefined {
@@ -105,7 +105,7 @@ assert(baseR(61, 62) === 'Z');
105
105
  assert(baseR(62, 62) === '10');
106
106
 
107
107
  export function signature(source: Element | DocumentFragment): string {
108
- assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))'));
108
+ assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))') || source.nodeName === 'MARK');
109
109
  const target = source.cloneNode(true) as typeof source;
110
110
  for (let es = target.querySelectorAll('code[data-src], .math[data-src], .label[data-label], .remark, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
111
111
  len = es.length, i = 0; i < len; ++i) {
@@ -116,11 +116,13 @@ export function signature(source: Element | DocumentFragment): string {
116
116
  continue;
117
117
  case 'RT':
118
118
  case 'RP':
119
- case 'BR':
120
119
  case 'UL':
121
120
  case 'OL':
122
121
  el.remove();
123
122
  continue;
123
+ case 'BR':
124
+ el.replaceWith('\n');
125
+ continue;
124
126
  }
125
127
  switch (el.className) {
126
128
  case 'math':
@@ -13,8 +13,8 @@ import { html, defrag } from 'typed-dom/dom';
13
13
 
14
14
  export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => validate('[', creation(1, Recursion.inline, surround(
15
15
  str(/^\[[:^|]/),
16
- syntax(2, State.none,
17
- startTight(some(union([inline]), ']', [[']', 2]]))),
16
+ syntax(1, State.none,
17
+ startTight(some(union([inline]), ']', [[']', 1]]))),
18
18
  str(']'), false,
19
19
  ([, bs], rest) => [[
20
20
  html('span', {
@@ -18,7 +18,7 @@ const attrspecs = {
18
18
  Object.setPrototypeOf(attrspecs, null);
19
19
  Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
20
20
 
21
- export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, creation(1, Recursion.inline, syntax(4, State.none, union([
21
+ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/i, creation(1, Recursion.inline, syntax(3, State.none, union([
22
22
  focus(
23
23
  /^<wbr[^\S\n]*>/i,
24
24
  () => [[h('wbr')], '']),
@@ -35,7 +35,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
35
35
  str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
36
36
  subsequence([
37
37
  focus(/^[^\S\n]*\n/, some(inline)),
38
- some(open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`), 4]]), true)),
38
+ some(open(/^\n?/, some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`), 3]]), true)),
39
39
  ]),
40
40
  str(`</${tag}>`), true,
41
41
  ([as, bs = [], cs], rest) =>
@@ -50,7 +50,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
50
50
  str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true),
51
51
  subsequence([
52
52
  focus(/^[^\S\n]*\n/, some(inline)),
53
- some(inline, `</${tag}>`, [[`</${tag}>`, 4]]),
53
+ some(inline, `</${tag}>`, [[`</${tag}>`, 3]]),
54
54
  ]),
55
55
  str(`</${tag}>`), true,
56
56
  ([as, bs = [], cs], rest) =>
@@ -208,7 +208,7 @@ const TAGS = Object.freeze([
208
208
 
209
209
  function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[]): HTMLElement {
210
210
  assert(as.length > 0);
211
- assert(as[0][0] === '<' && as[as.length - 1].slice(-1) === '>');
211
+ assert(as[0][0] === '<' && as.at(-1)!.slice(-1) === '>');
212
212
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag name "${tag}"`, as, bs, cs);
213
213
  if (cs.length === 0) return invalid('tag', `Missing the closing HTML tag "</${tag}>"`, as, bs, cs);
214
214
  if (bs.length === 0) return invalid('content', `Missing the content`, as, bs, cs);
@@ -5,20 +5,20 @@ import { html } from 'typed-dom/dom';
5
5
  import { reduce } from 'spica/memoize';
6
6
 
7
7
  export const unsafehtmlentity: UnsafeHTMLEntityParser = creation(1, Recursion.ignore, validate('&', focus(
8
- /^&[0-9A-Za-z]+;/,
8
+ /^&[0-9A-Za-z]{1,99};/,
9
9
  ({ source }) => [[parse(source) ?? `\x1B${source}`], ''])));
10
10
 
11
11
  export const htmlentity: HTMLEntityParser = fmap(
12
12
  union([unsafehtmlentity]),
13
- ([test]) => [
14
- test[0] === '\x1B'
13
+ ([text]) => [
14
+ text[0] === '\x1B'
15
15
  ? html('span', {
16
16
  class: 'invalid',
17
17
  'data-invalid-syntax': 'htmlentity',
18
18
  'data-invalid-type': 'syntax',
19
19
  'data-invalid-message': 'Invalid HTML entity',
20
- }, test.slice(1))
21
- : test,
20
+ }, text.slice(1))
21
+ : text,
22
22
  ]);
23
23
 
24
24
  const parse = reduce((el => (entity: string): string | undefined => {
@@ -9,7 +9,7 @@ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() => creation(1, Recursion.inline, surround(
11
11
  str('++', '+'),
12
- syntax(1, State.none,
12
+ syntax(0, State.none,
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '++')),
15
15
  open('\n', some(inline, '+'), true),
@@ -22,11 +22,11 @@ export const link: LinkParser = lazy(() => validate(['[', '{'], union([
22
22
 
23
23
  export const textlink: LinkParser.TextLinkParser = lazy(() => creation(1, Recursion.ignore,
24
24
  constraint(State.link, false,
25
- syntax(2, State.linkers | State.media,
25
+ syntax(1, State.linkers | State.media,
26
26
  bind(reverse(tails([
27
27
  dup(surround(
28
28
  '[',
29
- trimBlankStart(some(union([inline]), ']', [[/^\\?\n/, 9], [']', 2]])),
29
+ trimBlankStart(some(union([inline]), ']', [[/^\\?\n/, 9], [']', 1]])),
30
30
  ']',
31
31
  true, undefined, undefined, 1 | Backtrack.bracket)),
32
32
  dup(surround(
@@ -44,7 +44,7 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => creation(1, Recurs
44
44
 
45
45
  export const medialink: LinkParser.MediaLinkParser = lazy(() => creation(1, Recursion.ignore,
46
46
  constraint(State.link | State.media, false,
47
- syntax(2, State.linkers,
47
+ syntax(1, State.linkers,
48
48
  bind(reverse(sequence([
49
49
  dup(surround(
50
50
  '[',
@@ -61,7 +61,7 @@ export const linemedialink: LinkParser.LineMediaLinkParser = surround(
61
61
  /^(?=[^\S\n]*(?:$|\n))/);
62
62
 
63
63
  export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
64
- creation(1, Recursion.ignore, precedence(2,
64
+ creation(1, Recursion.ignore, precedence(1,
65
65
  bind(reverse(tails([
66
66
  dup(surround(
67
67
  '[',
@@ -15,10 +15,8 @@ describe('Unit: parser/inline/mark', () => {
15
15
  assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a'], ' ==']);
16
16
  assert.deepStrictEqual(inspect(parser('==a ==')), [['==', 'a', ' '], ' ==']);
17
17
  assert.deepStrictEqual(inspect(parser('==a\n==')), [['==', 'a'], '\n==']);
18
- assert.deepStrictEqual(inspect(parser('==a\nb==')), [['==', 'a'], '\nb==']);
19
18
  assert.deepStrictEqual(inspect(parser('==a\\ ==')), [['==', 'a'], '\\ ==']);
20
19
  assert.deepStrictEqual(inspect(parser('==a\\\n==')), [['==', 'a'], '\\\n==']);
21
- assert.deepStrictEqual(inspect(parser('==a\\\nb==')), [['==', 'a'], '\\\nb==']);
22
20
  assert.deepStrictEqual(inspect(parser('== ==')), undefined);
23
21
  assert.deepStrictEqual(inspect(parser('== a==')), undefined);
24
22
  assert.deepStrictEqual(inspect(parser('== a ==')), undefined);
@@ -33,6 +31,8 @@ describe('Unit: parser/inline/mark', () => {
33
31
  assert.deepStrictEqual(inspect(parser('==a=b==')), [['<mark id="mark::a=b=3lYfIw">a=b</mark>', '<a href="#mark::a=b=3lYfIw"></a>'], '']);
34
32
  assert.deepStrictEqual(inspect(parser('==\\===')), [['<mark id="mark::=">=</mark>', '<a href="#mark::="></a>'], '']);
35
33
  assert.deepStrictEqual(inspect(parser('==a===')), [['<mark id="mark::a">a</mark>', '<a href="#mark::a"></a>'], '=']);
34
+ assert.deepStrictEqual(inspect(parser('==a\nb==')), [['<mark id="mark::a_b=12Ta86">a<br>b</mark>', '<a href="#mark::a_b=12Ta86"></a>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('==a\\\nb==')), [['<mark id="mark::a_b=12Ta86">a<br>b</mark>', '<a href="#mark::a_b=12Ta86"></a>'], '']);
36
36
  });
37
37
 
38
38
  it('nest', () => {
@@ -11,10 +11,10 @@ import { html, define, defrag } from 'typed-dom/dom';
11
11
  export const mark: MarkParser = lazy(() => creation(1, Recursion.inline, surround(
12
12
  str('==', '='),
13
13
  constraint(State.mark, false,
14
- syntax(1, State.none,
14
+ syntax(0, State.none,
15
15
  startTight(some(union([
16
- some(inline, blankWith('=='), [[/^\\?\n/, 9]]),
17
- open(some(inline, '=', [[/^\\?\n/, 9]]), mark),
16
+ some(inline, blankWith('==')),
17
+ open(some(inline, '='), mark),
18
18
  ]))))),
19
19
  str('=='), false,
20
20
  ([, bs], rest, { id }) => {
@@ -8,10 +8,10 @@ const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
8
8
 
9
9
  export const math: MathParser = lazy(() => validate('$', creation(1, Recursion.ignore, rewrite(
10
10
  union([
11
- surround('$', precedence(6, bracket), '$'),
11
+ surround('$', precedence(5, bracket), '$'),
12
12
  surround(
13
13
  /^\$(?![\s{}])/,
14
- precedence(3, some(union([
14
+ precedence(2, some(union([
15
15
  bracket,
16
16
  focus(/^(?:[ ([](?!\$)|\\[\\{}$]?|[!#%&')\x2A-\x5A\]^_\x61-\x7A|~])+/, some(unescsource)),
17
17
  ]))),
@@ -21,7 +21,7 @@ Object.setPrototypeOf(optspec, null);
21
21
  export const media: MediaParser = lazy(() => validate(['![', '!{'], creation(1, Recursion.ignore, open(
22
22
  '!',
23
23
  constraint(State.media, false,
24
- syntax(2, ~State.link,
24
+ syntax(1, ~State.link,
25
25
  bind(verify(fmap(tails([
26
26
  dup(surround(
27
27
  '[',
@@ -78,7 +78,7 @@ const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(0, Rec
78
78
  undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
79
79
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
80
80
  undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
81
- surround(str('"'), precedence(3, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
81
+ surround(str('"'), precedence(2, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
82
82
  undefined, undefined, 3 | Backtrack.media),
83
83
  ])));
84
84
 
@@ -9,10 +9,10 @@ import { html, defrag } from 'typed-dom/dom';
9
9
  export const reference: ReferenceParser = lazy(() => creation(1, Recursion.ignore, surround(
10
10
  '[[',
11
11
  constraint(State.reference, false,
12
- syntax(6, State.annotation | State.reference | State.media,
12
+ syntax(1, State.annotation | State.reference | State.media,
13
13
  subsequence([
14
14
  abbr,
15
- trimBlankStart(some(inline, ']', [[/^\\?\n/, 9], [']', 2]])),
15
+ trimBlankStart(some(inline, ']', [[/^\\?\n/, 9], [']', 1]])),
16
16
  ]))),
17
17
  ']]',
18
18
  false,
@@ -7,13 +7,13 @@ import { memoize } from 'spica/memoize';
7
7
  import { unshift, push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
- export const remark: RemarkParser = lazy(() => validate('[%', creation(1, Recursion.inline, syntax(5, State.none, match(
10
+ export const remark: RemarkParser = lazy(() => validate('[%', creation(1, Recursion.inline, syntax(4, State.none, match(
11
11
  /^\[(%+)\s/,
12
12
  memoize(
13
13
  ([, fence]) =>
14
14
  surround(
15
15
  open(str(`[${fence}`), some(text, new RegExp(String.raw`^\s+${fence}\]|^\S`)), true),
16
- some(union([inline]), new RegExp(String.raw`^\s+${fence}\]`), [[new RegExp(String.raw`^\s+${fence}\]`), 5]]),
16
+ some(union([inline]), new RegExp(String.raw`^\s+${fence}\]`), [[new RegExp(String.raw`^\s+${fence}\]`), 4]]),
17
17
  close(some(text, /^\S/), str(`${fence}]`)), true,
18
18
  ([as, bs = [], cs], rest) => [[
19
19
  html('span', { class: 'remark' }, [
@@ -8,11 +8,11 @@ import { isStartTightNodes } from '../visibility';
8
8
  import { unshift, push } from 'spica/array';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
- export const ruby: RubyParser = lazy(() => validate('[', creation(1, Recursion.ignore, syntax(2, State.all, fmap(
11
+ export const ruby: RubyParser = lazy(() => validate('[', creation(1, Recursion.ignore, syntax(1, State.all, fmap(
12
12
  sequence([
13
13
  bind(surround('[', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
14
14
  const ns = eval(text({ source, context }), [undefined])[0];
15
- ns && ns[ns.length - 1] === '' && ns.pop();
15
+ ns && ns.at(-1) === '' && ns.pop();
16
16
  return ns && isStartTightNodes(ns) ? [[ns], rest] : undefined;
17
17
  }),
18
18
  bind(surround('(', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
@@ -12,10 +12,8 @@ describe('Unit: parser/inline/strong', () => {
12
12
  assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a'], ' **']);
13
13
  assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' '], ' **']);
14
14
  assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a'], '\n**']);
15
- assert.deepStrictEqual(inspect(parser('**a\nb**')), [['**', 'a'], '\nb**']);
16
15
  assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a'], '\\ **']);
17
16
  assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a'], '\\\n**']);
18
- assert.deepStrictEqual(inspect(parser('**a\\\nb**')), [['**', 'a'], '\\\nb**']);
19
17
  assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
20
18
  assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
21
19
  assert.deepStrictEqual(inspect(parser('** **')), undefined);
@@ -33,6 +31,8 @@ describe('Unit: parser/inline/strong', () => {
33
31
  it('basic', () => {
34
32
  assert.deepStrictEqual(inspect(parser('**a**')), [['<strong>a</strong>'], '']);
35
33
  assert.deepStrictEqual(inspect(parser('**ab**')), [['<strong>ab</strong>'], '']);
34
+ assert.deepStrictEqual(inspect(parser('**a\nb**')), [['<strong>a<br>b</strong>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('**a\\\nb**')), [['<strong>a<br>b</strong>'], '']);
36
36
  });
37
37
 
38
38
  it('nest', () => {
@@ -10,10 +10,10 @@ import { html, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const strong: StrongParser = lazy(() => creation(1, Recursion.inline, surround(
12
12
  str('**', '*'),
13
- syntax(1, State.none,
13
+ syntax(0, State.none,
14
14
  startTight(some(union([
15
- some(inline, blankWith('**'), [[/^\\?\n/, 9]]),
16
- open(some(inline, '*', [[/^\\?\n/, 9]]), union([
15
+ some(inline, blankWith('**')),
16
+ open(some(inline, '*'), union([
17
17
  emstrong,
18
18
  strong,
19
19
  ])),
@@ -7,7 +7,7 @@ import { html } from 'typed-dom/dom';
7
7
 
8
8
  export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore, surround(
9
9
  '{{',
10
- syntax(6, State.all, some(union([bracket, escsource]), '}', [['}}', 6]])),
10
+ syntax(1, State.all, some(union([bracket, escsource]), '}')),
11
11
  '}}',
12
12
  true,
13
13
  ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest],
@@ -20,6 +20,6 @@ const bracket: TemplateParser.BracketParser = lazy(() => creation(0, Recursion.t
20
20
  undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
21
21
  surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true,
22
22
  undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
23
- surround(str('"'), precedence(3, some(escsource, /^"|^\\?\n/)), str('"'), true,
23
+ surround(str('"'), precedence(2, some(escsource, /^"|^\\?\n/)), str('"'), true,
24
24
  undefined, undefined, 3 | Backtrack.template),
25
25
  ])));
@@ -105,6 +105,7 @@ describe('Unit: parser/inline', () => {
105
105
  assert.deepStrictEqual(inspect(parser('<bdi>*<bdi>a</bdi>*</bdi>')), [['<bdi><em><bdi>a</bdi></em></bdi>'], '']);
106
106
  assert.deepStrictEqual(inspect(parser('<bdi>((<bdi>((a))</bdi>))</bdi>')), [['<bdi><sup class="annotation"><span><bdi><span class="paren">((a))</span></bdi></span></sup></bdi>'], '']);
107
107
  assert.deepStrictEqual(inspect(parser('<bdi>[[<bdi>[[a]]</bdi>]]</bdi>')), [['<bdi><sup class="reference"><span><bdi>[[a]]</bdi></span></sup></bdi>'], '']);
108
+ assert.deepStrictEqual(inspect(parser('"<bdi>("")</bdi>')), [['"', '<bdi><span class="paren">("")</span></bdi>'], '']);
108
109
  assert.deepStrictEqual(inspect(parser('*[*]')), [['*', '[', '*', ']'], '']);
109
110
  assert.deepStrictEqual(inspect(parser('*<*>')), [['<em>&lt;</em>', '>'], '']);
110
111
  assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<em>a<sup class="annotation"><span>b</span></sup></em>'], '']);
@@ -150,7 +151,7 @@ describe('Unit: parser/inline', () => {
150
151
  assert.deepStrictEqual(inspect(parser('((((a))))')), [['<sup class="annotation"><span><span class="paren">((a))</span></span></sup>'], '']);
151
152
  assert.deepStrictEqual(inspect(parser('((${))}$')), [['(', '(', '<span class="math" translate="no" data-src="${))}$">${))}$</span>'], '']);
152
153
  assert.deepStrictEqual(inspect(parser('((a\nb))')), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
153
- assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '<sup class="annotation"><span>""</span></sup>'], '']);
154
+ assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '(', '(', '"', '"', ')', ')'], '']);
154
155
  assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
155
156
  assert.deepStrictEqual(inspect(parser('[[[[a]]')), [['[', '[', '<sup class="reference"><span>a</span></sup>'], '']);
156
157
  assert.deepStrictEqual(inspect(parser('[[[[a]]]]')), [['<sup class="reference"><span>[[a]]</span></sup>'], '']);
@@ -159,7 +160,7 @@ describe('Unit: parser/inline', () => {
159
160
  assert.deepStrictEqual(inspect(parser('[[[a]{b}]]')), [['<sup class="reference"><span><a class="link" href="b">a</a></span></sup>'], '']);
160
161
  assert.deepStrictEqual(inspect(parser('[(([a]{#}))]{#}')), [['<a class="link" href="#"><span class="paren">(<span class="paren">([a]{#})</span>)</span></a>'], '']);
161
162
  assert.deepStrictEqual(inspect(parser('[[${]]}$')), [['[', '[', '<span class="math" translate="no" data-src="${]]}$">${]]}$</span>'], '']);
162
- assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference"><span>""</span></sup>'], '']);
163
+ assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '[', '[', '"', '"', ']', ']'], '']);
163
164
  assert.deepStrictEqual(inspect(parser('[==a==]{b}')), [['<a class="link" href="b">==a==</a>'], '']);
164
165
  assert.deepStrictEqual(inspect(parser('[[a](b)]{c}')), [['<a class="link" href="c"><ruby>a<rp>(</rp><rt>b</rt><rp>)</rp></ruby></a>'], '']);
165
166
  assert.deepStrictEqual(inspect(parser('[[[[[[[{a}')), [['[', '[', '[', '[', '[', '[', '[', '<a class="url" href="a">a</a>'], '']);
@@ -171,6 +172,7 @@ describe('Unit: parser/inline', () => {
171
172
  assert.deepStrictEqual(inspect(parser('[^a@b')), [['[^', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
172
173
  assert.deepStrictEqual(inspect(parser('"[% *"*"*')), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
173
174
  assert.deepStrictEqual(inspect(parser('"[% "*"* %]')), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
175
+ assert.deepStrictEqual(inspect(parser('"{{""}}')), [['"', '{', '{', '"', '"', '}', '}'], '']);
174
176
  });
175
177
 
176
178
  it('uri', () => {