securemark 0.293.1 → 0.293.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/README.md +7 -10
  3. package/dist/index.js +329 -150
  4. package/package.json +1 -1
  5. package/src/combinator/control/manipulation/indent.test.ts +6 -1
  6. package/src/combinator/control/manipulation/indent.ts +1 -1
  7. package/src/combinator/control/manipulation/scope.ts +3 -4
  8. package/src/combinator/control/manipulation/surround.ts +2 -1
  9. package/src/combinator/data/parser/context/delimiter.ts +7 -12
  10. package/src/combinator/data/parser/some.ts +4 -8
  11. package/src/parser/api/parse.test.ts +2 -2
  12. package/src/parser/block/olist.test.ts +8 -6
  13. package/src/parser/block/olist.ts +2 -2
  14. package/src/parser/block/sidefence.ts +2 -2
  15. package/src/parser/block/table.ts +2 -2
  16. package/src/parser/block.ts +38 -36
  17. package/src/parser/inline/annotation.test.ts +1 -1
  18. package/src/parser/inline/autolink/url.test.ts +5 -5
  19. package/src/parser/inline/bracket.test.ts +6 -4
  20. package/src/parser/inline/bracket.ts +114 -88
  21. package/src/parser/inline/html.ts +24 -13
  22. package/src/parser/inline/italic.test.ts +9 -9
  23. package/src/parser/inline/link.ts +1 -1
  24. package/src/parser/inline/mark.test.ts +5 -5
  25. package/src/parser/inline/math.ts +2 -2
  26. package/src/parser/inline/media.ts +3 -2
  27. package/src/parser/inline/reference.test.ts +1 -1
  28. package/src/parser/inline/remark.ts +2 -2
  29. package/src/parser/inline/template.ts +1 -1
  30. package/src/parser/inline.test.ts +24 -23
  31. package/src/parser/inline.ts +46 -47
  32. package/src/parser/segment.ts +12 -12
  33. package/src/parser/source/escapable.test.ts +1 -1
  34. package/src/parser/source/escapable.ts +7 -4
  35. package/src/parser/source/text.ts +162 -25
  36. package/src/parser/source/unescapable.ts +5 -3
@@ -1,6 +1,6 @@
1
1
  import { BracketParser } from '../inline';
2
2
  import { State, Recursion, Backtrack } from '../context';
3
- import { union, some, recursion, precedence, validate, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
3
+ import { union, some, recursion, precedence, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { textlink } from './link';
6
6
  import { str } from '../source';
@@ -11,93 +11,119 @@ const indexA = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*$/;
11
11
  const indexF = new RegExp(indexA.source.replace(', ', '[,、]')
12
12
  .replace(/[09AZaz.]|\-(?!\w)/g, c => String.fromCodePoint(c.codePointAt(0)! + 0xFEE0)));
13
13
 
14
- export const bracket: BracketParser = lazy(() => validate(/[([{([{"]/y, union([
15
- surround(
16
- str('('),
17
- precedence(1, recursion(Recursion.bracket, some(inline, ')', [[')', 1]]))),
18
- str(')'),
19
- true,
20
- ([as, bs = [], cs], { source, position, range = 0 }) => {
21
- const str = source.slice(position - range + 1, position - 1);
22
- return indexA.test(str)
23
- ? [[as[0], str, cs[0]]]
24
- : [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))]];
25
- },
26
- ([as, bs = []]) => [unshift(as, bs)],
27
- [2 | Backtrack.bracket]),
28
- surround(
29
- str('('),
30
- precedence(1, recursion(Recursion.bracket, some(inline, '', [[')', 1]]))),
31
- str(')'),
32
- true,
33
- ([as, bs = [], cs], { source, position, range = 0 }) => {
34
- const str = source.slice(position - range + 1, position - 1);
35
- return indexF.test(str)
36
- ? [[as[0], str, cs[0]]]
37
- : [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))]];
38
- },
39
- ([as, bs = []]) => [unshift(as, bs)]),
40
- surround(
41
- str('['),
42
- precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
43
- str(']'),
44
- true,
45
- ([as, bs = [], cs], context) => {
46
- if (context.state! & State.link) {
47
- const { source, position, range = 0 } = context;
48
- const head = position - range;
49
- if (context.linebreak !== 0 || source[position] !== '{') {
14
+ export const bracket: BracketParser = lazy(() => union([
15
+ input => {
16
+ const { context: { source, position } } = input;
17
+ switch (source[position]) {
18
+ case '(':
19
+ return p1(input);
20
+ case '(':
21
+ return p2(input);
22
+ case '[':
23
+ return s1(input);
24
+ case '':
25
+ return s2(input);
26
+ case '{':
27
+ return c1(input);
28
+ case '{':
29
+ return c2(input);
30
+ case '"':
31
+ return d1(input);
32
+ }
33
+ }
34
+ ])) as any;
35
+
36
+ const p1 = lazy(() => surround(
37
+ str('('),
38
+ precedence(1, recursion(Recursion.bracket, some(inline, ')', [[')', 1]]))),
39
+ str(')'),
40
+ true,
41
+ ([as, bs = [], cs], { source, position, range = 0 }) => {
42
+ const str = source.slice(position - range + 1, position - 1);
43
+ return indexA.test(str)
44
+ ? [[as[0], str, cs[0]]]
45
+ : [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))]];
46
+ },
47
+ ([as, bs = []]) => [unshift(as, bs)],
48
+ [2 | Backtrack.bracket]));
49
+
50
+ const p2 = lazy(() => surround(
51
+ str('('),
52
+ precedence(1, recursion(Recursion.bracket, some(inline, ')', [[')', 1]]))),
53
+ str(')'),
54
+ true,
55
+ ([as, bs = [], cs], { source, position, range = 0 }) => {
56
+ const str = source.slice(position - range + 1, position - 1);
57
+ return indexF.test(str)
58
+ ? [[as[0], str, cs[0]]]
59
+ : [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))]];
60
+ },
61
+ ([as, bs = []]) => [unshift(as, bs)],
62
+ [2 | Backtrack.bracket]));
63
+
64
+ const s1 = lazy(() => surround(
65
+ str('['),
66
+ precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
67
+ str(']'),
68
+ true,
69
+ ([as, bs = [], cs], context) => {
70
+ if (context.state! & State.link) {
71
+ const { source, position, range = 0 } = context;
72
+ const head = position - range;
73
+ if (context.linebreak !== 0 || source[position] !== '{') {
74
+ setBacktrack(context, [2 | Backtrack.link], head);
75
+ }
76
+ else {
77
+ context.state! ^= State.link;
78
+ const result = !isBacktrack(context, [1 | Backtrack.link])
79
+ ? textlink({ context })
80
+ : undefined;
81
+ context.position = position;
82
+ if (!result) {
50
83
  setBacktrack(context, [2 | Backtrack.link], head);
51
84
  }
52
- else {
53
- context.state! ^= State.link;
54
- const result = !isBacktrack(context, [1 | Backtrack.link])
55
- ? textlink({ context })
56
- : undefined;
57
- context.position = position;
58
- if (!result) {
59
- setBacktrack(context, [2 | Backtrack.link], head);
60
- }
61
- context.state! ^= State.link;
62
- context.range = range;
63
- }
85
+ context.state! ^= State.link;
86
+ context.range = range;
64
87
  }
65
- return [push(unshift(as, bs), cs)];
66
- },
67
- ([as, bs = []]) => [unshift(as, bs)],
68
- [2 | Backtrack.bracket]),
69
- surround(
70
- str('['),
71
- precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
72
- str(''),
73
- true,
74
- undefined,
75
- ([as, bs = []]) => [unshift(as, bs)]),
76
- surround(
77
- str('{'),
78
- precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
79
- str('}'),
80
- true,
81
- undefined,
82
- ([as, bs = []]) => [unshift(as, bs)],
83
- [2 | Backtrack.bracket]),
84
- surround(
85
- str('{'),
86
- precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
87
- str('}'),
88
- true,
89
- undefined,
90
- ([as, bs = []]) => [unshift(as, bs)]),
91
- // 同一行内でしか閉じない以外括弧と同じ挙動
92
- surround(
93
- str('"'),
94
- precedence(2, recursion(Recursion.bracket, some(inline, '"', [['"', 2, false]]))),
95
- str('"'),
96
- true,
97
- ([as, bs = [], cs], context) =>
98
- context.linebreak === 0
99
- ? [push(unshift(as, bs), cs)]
100
- : (context.position -= 1, [unshift(as, bs)]),
101
- ([as, bs = []]) => [unshift(as, bs)],
102
- [2 | Backtrack.bracket]),
103
- ])));
88
+ }
89
+ return [push(unshift(as, bs), cs)];
90
+ },
91
+ ([as, bs = []]) => [unshift(as, bs)],
92
+ [2 | Backtrack.bracket]));
93
+
94
+ const s2 = lazy(() => surround(
95
+ str(''),
96
+ precedence(1, recursion(Recursion.bracket, some(inline, ']', [[']', 1]]))),
97
+ str(']'),
98
+ true,
99
+ undefined,
100
+ ([as, bs = []]) => [unshift(as, bs)],
101
+ [2 | Backtrack.bracket]));
102
+
103
+ const c1 = lazy(() => surround(
104
+ str('{'),
105
+ precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
106
+ str('}'),
107
+ true,
108
+ undefined,
109
+ ([as, bs = []]) => [unshift(as, bs)],
110
+ [2 | Backtrack.bracket]));
111
+
112
+ const c2 = lazy(() => surround(
113
+ str('{'),
114
+ precedence(1, recursion(Recursion.bracket, some(inline, '}', [['}', 1]]))),
115
+ str('}'),
116
+ true,
117
+ undefined,
118
+ ([as, bs = []]) => [unshift(as, bs)],
119
+ [2 | Backtrack.bracket]));
120
+
121
+ const d1 = lazy(() => surround(
122
+ str('"'),
123
+ // 改行の優先度を構文ごとに変える場合シグネチャの優先度対応が必要
124
+ precedence(2, recursion(Recursion.bracket, some(inline, /["\n]/y, [['"', 2], ['\n', 3]]))),
125
+ str('"'),
126
+ true,
127
+ undefined,
128
+ ([as, bs = []]) => [unshift(as, bs)],
129
+ [2 | Backtrack.bracket]));
@@ -7,7 +7,7 @@ import { str } from '../source';
7
7
  import { isLooseNodeStart, blankWith } from '../visibility';
8
8
  import { invalid } from '../util';
9
9
  import { memoize } from 'spica/memoize';
10
- import { unshift, push, splice } from 'spica/array';
10
+ import { unshift, push } from 'spica/array';
11
11
  import { html as h, defrag } from 'typed-dom/dom';
12
12
 
13
13
  const tags: readonly string[] = ['wbr', 'bdo', 'bdi'];
@@ -42,10 +42,14 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[^\S\n]|>)/yi,
42
42
  true,
43
43
  ([as, bs = [], cs]) => [push(unshift(as, bs), cs)],
44
44
  ([as, bs = []]) => [unshift(as, bs)]),
45
- precedence(3, recursion(Recursion.inline,
45
+ // 不可視のHTML構造が可視構造を変化させるべきでない。
46
+ // 可視のHTMLは優先度変更を検討する。
47
+ // このため<>は将来的に共通構造を変化させる可能性があり
48
+ // 共通構造を変更させない非構造文字列としては依然としてエスケープを要する。
49
+ precedence(0, recursion(Recursion.inline,
46
50
  some(union([
47
- some(inline, blankWith('\n', `</${tag}>`), [[blankWith('\n', `</${tag}>`), 3]]),
48
- open('\n', some(inline, `</${tag}>`, [[`</${tag}>`, 3]]), true),
51
+ some(inline, blankWith('\n', `</${tag}>`)),
52
+ open('\n', some(inline, `</${tag}>`), true),
49
53
  ])))),
50
54
  str(`</${tag}>`),
51
55
  true,
@@ -81,7 +85,7 @@ function elem(tag: string, content: boolean, as: string[], bs: (HTMLElement | st
81
85
  if (bs.length === 0) return ielem('content', `Missing the content`, context);
82
86
  if (!isLooseNodeStart(bs)) return ielem('content', `Missing the visible content in the same line`, context);
83
87
  }
84
- const attrs = attributes('html', attrspecs[tag], as.slice(1, as.at(-1) === '>' ? -1 : as.length));
88
+ const [attrs] = attributes('html', attrspecs[tag], as.slice(1, as.at(-1) === '>' ? -1 : as.length));
85
89
  if (/(?<!\S)invalid(?!\S)/.test(attrs['class'] ?? '')) return ielem('attribute', 'Invalid HTML attribute', context)
86
90
  if (as.at(-1) !== '>') return ielem('tag', `Missing the closing symbol ">"`, context);
87
91
  return h(tag as 'span', attrs, defrag(bs));
@@ -101,11 +105,12 @@ const requiredAttributes = memoize(
101
105
  export function attributes(
102
106
  syntax: string,
103
107
  spec: Readonly<Record<string, readonly (string | undefined)[] | undefined>> | undefined,
104
- params: string[],
105
- ): Record<string, string | undefined> {
108
+ params: readonly string[],
109
+ ): [Record<string, string | undefined>, string[]] {
106
110
  assert(spec instanceof Object === false);
107
111
  assert(!spec?.['__proto__']);
108
112
  assert(!spec?.toString);
113
+ const remains = [];
109
114
  let invalidation = false;
110
115
  const attrs: Record<string, string | undefined> = {};
111
116
  for (let i = 0; i < params.length; ++i) {
@@ -116,19 +121,25 @@ export function attributes(
116
121
  ? param.slice(name.length + 2, -1).replace(/\\(.?)/g, '$1')
117
122
  : undefined;
118
123
  invalidation ||= name === '' || !spec || name in attrs;
119
- if (name === '' || spec && name in spec && !spec[name]) continue;
120
- spec?.[name]?.includes(value) || spec?.[name]?.length === 0 && value !== undefined
121
- ? attrs[name] = value ?? ''
122
- : invalidation ||= !!spec;
124
+ if (name === '')continue;
125
+ if (spec && name in spec && !spec[name]) {
126
+ remains.push(params[i]);
127
+ continue;
128
+ }
129
+ if (spec?.[name]?.includes(value) || spec?.[name]?.length === 0 && value !== undefined) {
130
+ attrs[name] = value ?? ''
131
+ }
132
+ else {
133
+ invalidation ||= !!spec;
134
+ }
123
135
  assert(!(name in {} && attrs.hasOwnProperty(name)));
124
- splice(params, i--, 1);
125
136
  }
126
137
  invalidation ||= !!spec && !requiredAttributes(spec).every(name => name in attrs);
127
138
  if (invalidation) {
128
139
  attrs['class'] = 'invalid';
129
140
  Object.assign(attrs, invalid(syntax, 'argument', 'Invalid argument'));
130
141
  }
131
- return attrs;
142
+ return [attrs, remains];
132
143
  }
133
144
 
134
145
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Element
@@ -11,14 +11,14 @@ describe('Unit: parser/inline/italic', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser('///'), ctx), undefined);
13
13
  assert.deepStrictEqual(inspect(parser('///a'), ctx), [['///', 'a'], '']);
14
- assert.deepStrictEqual(inspect(parser('///a ///'), ctx), [['///', 'a', ' ', '/', '/', '/'], '']);
15
- assert.deepStrictEqual(inspect(parser('///a ///'), ctx), [['///', 'a', ' ', '/', '/', '/'], '']);
16
- assert.deepStrictEqual(inspect(parser('///a\n///'), ctx), [['///', 'a', '<br>', '/', '/', '/'], '']);
17
- assert.deepStrictEqual(inspect(parser('///a\\ ///'), ctx), [['///', 'a', ' ', '/', '/', '/'], '']);
18
- assert.deepStrictEqual(inspect(parser('///a\\\n///'), ctx), [['///', 'a', '<br>', '/', '/', '/'], '']);
14
+ assert.deepStrictEqual(inspect(parser('///a ///'), ctx), [['///', 'a', ' ', '///'], '']);
15
+ assert.deepStrictEqual(inspect(parser('///a ///'), ctx), [['///', 'a', ' ', '///'], '']);
16
+ assert.deepStrictEqual(inspect(parser('///a\n///'), ctx), [['///', 'a', '<br>', '///'], '']);
17
+ assert.deepStrictEqual(inspect(parser('///a\\ ///'), ctx), [['///', 'a', ' ', '///'], '']);
18
+ assert.deepStrictEqual(inspect(parser('///a\\\n///'), ctx), [['///', 'a', '<br>', '///'], '']);
19
19
  assert.deepStrictEqual(inspect(parser('///a/b'), ctx), [['///', 'a', '/b'], '']);
20
- assert.deepStrictEqual(inspect(parser('///a//b'), ctx), [['///', 'a', '/', '/b'], '']);
21
- assert.deepStrictEqual(inspect(parser('///a*b///'), ctx), [['///', 'a', '*', 'b', '/', '/', '/'], '']);
20
+ assert.deepStrictEqual(inspect(parser('///a//b'), ctx), [['///', 'a', '//b'], '']);
21
+ assert.deepStrictEqual(inspect(parser('///a*b///'), ctx), [['///', 'a', '*', 'b', '///'], '']);
22
22
  assert.deepStrictEqual(inspect(parser('/// ///'), ctx), undefined);
23
23
  assert.deepStrictEqual(inspect(parser('/// a///'), ctx), undefined);
24
24
  assert.deepStrictEqual(inspect(parser('/// a ///'), ctx), undefined);
@@ -53,8 +53,8 @@ describe('Unit: parser/inline/italic', () => {
53
53
  assert.deepStrictEqual(inspect(parser('//////a///b'), ctx), [['///', '<i>a</i>', 'b'], '']);
54
54
  assert.deepStrictEqual(inspect(parser('//////a////'), ctx), [['///', '<i>a</i>', '/'], '']);
55
55
  assert.deepStrictEqual(inspect(parser('//////a////b'), ctx), [['///', '<i>a</i>', '/b'], '']);
56
- assert.deepStrictEqual(inspect(parser('//////a/////'), ctx), [['///', '<i>a</i>', '/', '/'], '']);
57
- assert.deepStrictEqual(inspect(parser('//////a/////b'), ctx), [['///', '<i>a</i>', '/', '/b'], '']);
56
+ assert.deepStrictEqual(inspect(parser('//////a/////'), ctx), [['///', '<i>a</i>', '//'], '']);
57
+ assert.deepStrictEqual(inspect(parser('//////a/////b'), ctx), [['///', '<i>a</i>', '//b'], '']);
58
58
  assert.deepStrictEqual(inspect(parser('//////a//////'), ctx), [['<i><i>a</i></i>'], '']);
59
59
  assert.deepStrictEqual(inspect(parser('//////a///b///'), ctx), [['<i><i>a</i>b</i>'], '']);
60
60
  assert.deepStrictEqual(inspect(parser('///a ///b//////'), ctx), [['<i>a <i>b</i></i>'], '']);
@@ -135,7 +135,7 @@ function parse(
135
135
  context.host?.origin || location.origin);
136
136
  return el.classList.contains('invalid')
137
137
  ? el
138
- : define(el, attributes('link', optspec, params));
138
+ : define(el, attributes('link', optspec, params)[0]);
139
139
  }
140
140
 
141
141
  function elem(
@@ -14,11 +14,11 @@ describe('Unit: parser/inline/mark', () => {
14
14
  assert.deepStrictEqual(inspect(parser('=='), ctx), undefined);
15
15
  assert.deepStrictEqual(inspect(parser('==a'), ctx), [['==', 'a'], '']);
16
16
  assert.deepStrictEqual(inspect(parser('==a='), ctx), [['==', 'a', '='], '']);
17
- assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=', '='], '']);
18
- assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=', '='], '']);
19
- assert.deepStrictEqual(inspect(parser('==a\n=='), ctx), [['==', 'a', '<br>', '=', '='], '']);
20
- assert.deepStrictEqual(inspect(parser('==a\\ =='), ctx), [['==', 'a', ' ', '=', '='], '']);
21
- assert.deepStrictEqual(inspect(parser('==a\\\n=='), ctx), [['==', 'a', '<br>', '=', '='], '']);
17
+ assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=='], '']);
18
+ assert.deepStrictEqual(inspect(parser('==a =='), ctx), [['==', 'a', ' ', '=='], '']);
19
+ assert.deepStrictEqual(inspect(parser('==a\n=='), ctx), [['==', 'a', '<br>', '=='], '']);
20
+ assert.deepStrictEqual(inspect(parser('==a\\ =='), ctx), [['==', 'a', ' ', '=='], '']);
21
+ assert.deepStrictEqual(inspect(parser('==a\\\n=='), ctx), [['==', 'a', '<br>', '=='], '']);
22
22
  assert.deepStrictEqual(inspect(parser('== =='), ctx), undefined);
23
23
  assert.deepStrictEqual(inspect(parser('== a=='), ctx), undefined);
24
24
  assert.deepStrictEqual(inspect(parser('== a =='), ctx), undefined);
@@ -11,14 +11,14 @@ export const math: MathParser = lazy(() => rewrite(
11
11
  union([
12
12
  surround(
13
13
  /\$(?={)/y,
14
- precedence(5, bracket),
14
+ precedence(4, bracket),
15
15
  '$',
16
16
  false, undefined, undefined, [3 | Backtrack.bracket]),
17
17
  surround(
18
18
  /\$(?![\s{}])/y,
19
19
  precedence(2, some(union([
20
20
  some(escsource, /\s?\$|[`"{}\n]/y),
21
- precedence(5, bracket),
21
+ precedence(4, bracket),
22
22
  ]))),
23
23
  /\$(?![-0-9A-Za-z])/y,
24
24
  false, undefined, undefined, [3 | Backtrack.bracket]),
@@ -87,7 +87,8 @@ export const media: MediaParser = lazy(() => constraint(State.media, creation(10
87
87
  el.setAttribute('alt', text);
88
88
  if (!sanitize(el, uri)) return [[el]];
89
89
  assert(!el.matches('.invalid'));
90
- define(el, attributes('media', optspec, params));
90
+ const [attrs, linkparams] = attributes('media', optspec, params);
91
+ define(el, attrs);
91
92
  assert(el.matches('img') || !el.matches('.invalid'));
92
93
  // Awaiting the generic support for attr().
93
94
  if (el.hasAttribute('aspect-ratio')) {
@@ -103,7 +104,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, creation(10
103
104
  context.position = position;
104
105
  return [define(link, { class: null, target: '_blank' }, [el])];
105
106
  })
106
- (subinput(`{ ${INSECURE_URI}${params.join('')} }`, context));
107
+ (subinput(`{ ${INSECURE_URI}${linkparams.join('')} }`, context));
107
108
  })))));
108
109
 
109
110
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => recursion(Recursion.terminal, union([
@@ -17,7 +17,7 @@ describe('Unit: parser/inline/reference', () => {
17
17
  assert.deepStrictEqual(inspect(parser('[[]]]'), ctx), undefined);
18
18
  assert.deepStrictEqual(inspect(parser('[["]]'), ctx), undefined);
19
19
  assert.deepStrictEqual(inspect(parser('[[(]]'), ctx), undefined);
20
- assert.deepStrictEqual(inspect(parser('[[<bdi>]]'), ctx), undefined);
20
+ assert.deepStrictEqual(inspect(parser('[[[%]]'), ctx), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('[[ ]]'), ctx), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('[[ [a'), ctx), undefined);
23
23
  assert.deepStrictEqual(inspect(parser('[[\n]]'), ctx), undefined);
@@ -9,8 +9,8 @@ import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const remark: RemarkParser = lazy(() => fallback(surround(
11
11
  str(/\[%(?=\s)/y),
12
- precedence(4, recursion(Recursion.inline,
13
- some(union([inline]), /\s%\]/y, [[/\s%\]/y, 4]]))),
12
+ precedence(3, recursion(Recursion.inline,
13
+ some(union([inline]), /\s%\]/y, [[/\s%\]/y, 3]]))),
14
14
  close(text, str(`%]`)), true,
15
15
  ([as, bs = [], cs]) => [[
16
16
  html('span', { class: 'remark' }, [
@@ -34,7 +34,7 @@ const bracket: TemplateParser.BracketParser = lazy(() => union([
34
34
  undefined, () => [[]], [3 | Backtrack.escbracket]),
35
35
  surround(
36
36
  str('"'),
37
- precedence(2, recursion(Recursion.terminal, some(escsource, '"', [['"', 2, false]]))),
37
+ precedence(2, recursion(Recursion.terminal, some(escsource, /["\n]/y, [['"', 2], ['\n', 3]]))),
38
38
  str('"'),
39
39
  true,
40
40
  ([as, bs = [], cs], context) =>
@@ -22,7 +22,7 @@ describe('Unit: parser/inline', () => {
22
22
  it('nest', () => {
23
23
  assert.deepStrictEqual(inspect(parser('あ(A)'), ctx), [['あ', '(', 'A', ')'], '']);
24
24
  assert.deepStrictEqual(inspect(parser('あ(い)'), ctx), [['あ', '<span class="paren">(い)</span>'], '']);
25
- assert.deepStrictEqual(inspect(parser('* a*'), ctx), [['*', ' a', '*'], '']);
25
+ assert.deepStrictEqual(inspect(parser('* a*'), ctx), [['* a', '*'], '']);
26
26
  assert.deepStrictEqual(inspect(parser('** a**'), ctx), [['**', ' a', '**'], '']);
27
27
  assert.deepStrictEqual(inspect(parser('*** a***'), ctx), [['***', ' a', '***'], '']);
28
28
  assert.deepStrictEqual(inspect(parser('**** a****'), ctx), [['****', ' a', '****'], '']);
@@ -82,19 +82,19 @@ describe('Unit: parser/inline', () => {
82
82
  assert.deepStrictEqual(inspect(parser('*++ a ++*'), ctx), [['<em><ins> a </ins></em>'], '']);
83
83
  assert.deepStrictEqual(inspect(parser('*++ a ++*'), ctx), [['<em><ins> a </ins></em>'], '']);
84
84
  assert.deepStrictEqual(inspect(parser('*<bdi>`a`</bdi>*'), ctx), [['<em><bdi><code data-src="`a`">a</code></bdi></em>'], '']);
85
- assert.deepStrictEqual(inspect(parser('*a"\nb*'), ctx), [['*', 'a', '"', '<br>', 'b', '*'], '']);
85
+ assert.deepStrictEqual(inspect(parser('*a"\nb*'), ctx), [['<em>a"<br>b</em>'], '']);
86
86
  assert.deepStrictEqual(inspect(parser('*a"\n"("b*'), ctx), [['<em>a"<br>"("b</em>'], '']);
87
- assert.deepStrictEqual(inspect(parser('"*a\nb*'), ctx), [['"', '<em>a<br>b</em>'], '']);
88
- assert.deepStrictEqual(inspect(parser('"*a\n""b*'), ctx), [['"', '<em>a<br>""b</em>'], '']);
87
+ assert.deepStrictEqual(inspect(parser('"*a\nb*'), ctx), [['"', '*', 'a', '<br>', 'b', '*'], '']);
88
+ assert.deepStrictEqual(inspect(parser('"*a\n""b*'), ctx), [['"', '*', 'a', '<br>', '"', '"', 'b', '*'], '']);
89
89
  assert.deepStrictEqual(inspect(parser('"a\n"*b"c*'), ctx), [['"', 'a', '<br>', '"', '*', 'b', '"', 'c', '*'], '']);
90
- assert.deepStrictEqual(inspect(parser('"*a**b\nc**"("*'), ctx), [['"', '<em>a<strong>b<br>c</strong>"("</em>'], '']);
91
- assert.deepStrictEqual(inspect(parser('<bdi>a"\nb</bdi>'), ctx), [['<bdi>a"<br>b</bdi>'], '']);
92
- assert.deepStrictEqual(inspect(parser('"<bdi>"a\n""b</bdi>"'), ctx), [['"', '<bdi>"a<br>""b</bdi>', '"'], '']);
90
+ assert.deepStrictEqual(inspect(parser('"*a**b\nc**"("*'), ctx), [['"', '*', 'a', '**', 'b', '<br>', 'c', '**', '"', '(', '"', '*'], '']);
91
+ assert.deepStrictEqual(inspect(parser('[% a"\nb %]'), ctx), [['<span class="remark"><input type="checkbox"><span>[% a"<br>b %]</span></span>'], '']);
92
+ assert.deepStrictEqual(inspect(parser('"<bdi>"a\n""b</bdi>"'), ctx), [['"', '<span class="invalid">&lt;bdi&gt;</span>', '"', 'a', '<br>', '"', '"', 'b', '</bdi', '>', '"'], '']);
93
93
  assert.deepStrictEqual(inspect(parser('<bdi>*<bdi>a</bdi>*</bdi>'), ctx), [['<bdi><em><bdi>a</bdi></em></bdi>'], '']);
94
94
  assert.deepStrictEqual(inspect(parser('<bdi>((<bdi>((a))</bdi>))</bdi>'), ctx), [['<bdi><sup class="annotation"><span><bdi><span class="paren">((a))</span></bdi></span></sup></bdi>'], '']);
95
95
  assert.deepStrictEqual(inspect(parser('<bdi>[[<bdi>[[a]]</bdi>]]</bdi>'), ctx), [['<bdi><sup class="reference"><span><bdi>[[a]]</bdi></span></sup></bdi>'], '']);
96
- assert.deepStrictEqual(inspect(parser('<bdi>[#</bdi>]'), ctx), [['<bdi>[#</bdi>', ']'], '']);
97
- assert.deepStrictEqual(inspect(parser('"<bdi>("")</bdi>'), ctx), [['"', '<bdi><span class="paren">("")</span></bdi>'], '']);
96
+ assert.deepStrictEqual(inspect(parser('<bdi>[#</bdi>]'), ctx), [['<span class="invalid">&lt;bdi&gt;[#&lt;/bdi&gt;]</span>'], '']);
97
+ assert.deepStrictEqual(inspect(parser('"<bdi>("")</bdi>'), ctx), [['"', '<span class="invalid">&lt;bdi&gt;(</span>', '"', '"', ')', '</bdi', '>'], '']);
98
98
  assert.deepStrictEqual(inspect(parser('++\na\n++\n~~\nb\n~~\nc'), ctx), [['<ins><br>a</ins>', '<br>', '<del><br>b</del>', '<br>', 'c'], '']);
99
99
  assert.deepStrictEqual(inspect(parser('[@a]'), ctx), [['[', '<a class="account" href="/@a">@a</a>', ']'], '']);
100
100
  assert.deepStrictEqual(inspect(parser('[#1][#2]'), ctx), [['<a class="index" href="#index::1">1</a>', '<a class="index" href="#index::2">2</a>'], '']);
@@ -121,11 +121,11 @@ describe('Unit: parser/inline', () => {
121
121
  assert.deepStrictEqual(inspect(parser('{}'), ctx), [['{', '}'], '']);
122
122
  assert.deepStrictEqual(inspect(parser('{a}'), ctx), [['<a class="url" href="a">a</a>'], '']);
123
123
  assert.deepStrictEqual(inspect(parser('{{a}}'), ctx), [['<span class="template">{{a}}</span>'], '']);
124
- assert.deepStrictEqual(inspect(parser('\r!{}'), ctx), [['!', '{', '}'], '']);
125
- assert.deepStrictEqual(inspect(parser('\r!{a}'), ctx), [['!', '<a class="url" href="a">a</a>'], '']);
126
- assert.deepStrictEqual(inspect(parser('\r!{{a}}'), ctx), [['!', '<span class="template">{{a}}</span>'], '']);
127
- assert.deepStrictEqual(inspect(parser('\r!{{{a}}}'), ctx), [['!', '<span class="template">{{{a}}}</span>'], '']);
128
- assert.deepStrictEqual(inspect(parser('\r!!{a}'), ctx), [['!', '!', '<a class="url" href="a">a</a>'], '']);
124
+ assert.deepStrictEqual(inspect(parser('!{}'), ctx), [['!', '{', '}'], '']);
125
+ assert.deepStrictEqual(inspect(parser('!{a}'), ctx), [['!', '<a class="url" href="a">a</a>'], '']);
126
+ assert.deepStrictEqual(inspect(parser('!{{a}}'), ctx), [['!', '<span class="template">{{a}}</span>'], '']);
127
+ assert.deepStrictEqual(inspect(parser('!{{{a}}}'), ctx), [['!', '<span class="template">{{{a}}}</span>'], '']);
128
+ assert.deepStrictEqual(inspect(parser('!!{a}'), ctx), [['!', '!', '<a class="url" href="a">a</a>'], '']);
129
129
  assert.deepStrictEqual(inspect(parser('${a}'), ctx), [['$', '<a class="url" href="a">a</a>'], '']);
130
130
  assert.deepStrictEqual(inspect(parser('${{a}}'), ctx), [['$', '<span class="template">{{a}}</span>'], '']);
131
131
  assert.deepStrictEqual(inspect(parser('${{{a}}}'), ctx), [['$', '<span class="template">{{{a}}}</span>'], '']);
@@ -165,16 +165,16 @@ describe('Unit: parser/inline', () => {
165
165
  assert.deepStrictEqual(inspect(parser('"[% *"*"*'), ctx), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
166
166
  assert.deepStrictEqual(inspect(parser('"[% "*"* %]'), ctx), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
167
167
  assert.deepStrictEqual(inspect(parser('"{{""}}'), ctx), [['"', '{', '{', '"', '"', '}', '}'], '']);
168
- assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(&lt;bdi&gt;)">http://host/(&lt;bdi&gt;)</a>', '<', '/bdi', '>'], '']);
169
- assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(&lt;bdi&gt;)">@a/http://host/(&lt;bdi&gt;)</a>', '<', '/bdi', '>'], '']);
170
- assert.deepStrictEqual(inspect(parser('[#a|<bdi>]</bdi>'), ctx), [['[', '<a class="hashtag" href="/hashtags/a">#a</a>', '|', '<bdi>]</bdi>'], '']);
171
- assert.deepStrictEqual(inspect(parser('[[#a|<bdi>]</bdi>'), ctx), [['[', '[', '<a class="hashtag" href="/hashtags/a">#a</a>', '|', '<bdi>]</bdi>'], '']);
168
+ assert.deepStrictEqual(inspect(parser('[#http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::http://host/(&lt;bdi&gt;)">http://host/(&lt;bdi&gt;)</a>', '</bdi', '>'], '']);
169
+ assert.deepStrictEqual(inspect(parser('[#@a/http://host/(<bdi>)]</bdi>'), ctx), [['<a class="index" href="#index::@a/http://host/(&lt;bdi&gt;)">@a/http://host/(&lt;bdi&gt;)</a>', '</bdi', '>'], '']);
170
+ assert.deepStrictEqual(inspect(parser('[#a|<bdi>]</bdi>'), ctx), [['<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
171
+ assert.deepStrictEqual(inspect(parser('[[#a|<bdi>]</bdi>'), ctx), [['[', '<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
172
172
  });
173
173
 
174
174
  it('uri', () => {
175
175
  assert.deepStrictEqual(inspect(parser('\nhttp://host'), ctx), [['<br>', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
176
- assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http:', '/', '/host'], '']);
177
- assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp:', '/', '/host'], '']);
176
+ assert.deepStrictEqual(inspect(parser('0http://host'), ctx), [['0http:', '//host'], '']);
177
+ assert.deepStrictEqual(inspect(parser('0aAhttp://host'), ctx), [['0aAhttp:', '//host'], '']);
178
178
  assert.deepStrictEqual(inspect(parser('?http://host'), ctx), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
179
179
  assert.deepStrictEqual(inspect(parser('0!http://host'), ctx), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
180
180
  assert.deepStrictEqual(inspect(parser('0?http://host'), ctx), [['0', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
@@ -196,7 +196,8 @@ describe('Unit: parser/inline', () => {
196
196
  assert.deepStrictEqual(inspect(parser('*a@b*'), ctx), [['<em><a class="email" href="mailto:a@b">a@b</a></em>'], '']);
197
197
  assert.deepStrictEqual(inspect(parser('(a@b)'), ctx), [['<span class="paren">(<a class="email" href="mailto:a@b">a@b</a>)</span>'], '']);
198
198
  assert.deepStrictEqual(inspect(parser(' a@b'), ctx), [[' ', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
199
- assert.deepStrictEqual(inspect(parser('++a++b@c++'), ctx), [['<ins>a</ins>', '<a class="email" href="mailto:b@c">b@c</a>', '+', '+'], '']);
199
+ assert.deepStrictEqual(inspect(parser('++a@b++'), ctx), [['<ins><a class="email" href="mailto:a@b">a@b</a></ins>'], '']);
200
+ assert.deepStrictEqual(inspect(parser('++a++b@c++'), ctx), [['<ins>a</ins>', '<a class="email" href="mailto:b@c">b@c</a>', '++'], '']);
200
201
  });
201
202
 
202
203
  it('channel', () => {
@@ -209,7 +210,7 @@ describe('Unit: parser/inline', () => {
209
210
 
210
211
  it('account', () => {
211
212
  assert.deepStrictEqual(inspect(parser('@a'), ctx), [['<a class="account" href="/@a">@a</a>'], '']);
212
- assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http', ':', '/', '/host'], '']);
213
+ assert.deepStrictEqual(inspect(parser('@http://host'), ctx), [['@http', '://host'], '']);
213
214
  assert.deepStrictEqual(inspect(parser('_@a'), ctx), [['_', '<a class="account" href="/@a">@a</a>'], '']);
214
215
  assert.deepStrictEqual(inspect(parser('_@a_'), ctx), [['_', '<a class="account" href="/@a">@a</a>', '_'], '']);
215
216
  assert.deepStrictEqual(inspect(parser('*@a*'), ctx), [['<em><a class="account" href="/@a">@a</a></em>'], '']);
@@ -221,7 +222,7 @@ describe('Unit: parser/inline', () => {
221
222
  assert.deepStrictEqual(inspect(parser('#a#'), ctx), [['#a', '#'], '']);
222
223
  assert.deepStrictEqual(inspect(parser('#a#b'), ctx), [['#a', '#b'], '']);
223
224
  assert.deepStrictEqual(inspect(parser('#a'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
224
- assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#http', ':', '/', '/host'], '']);
225
+ assert.deepStrictEqual(inspect(parser('#http://host'), ctx), [['#http', '://host'], '']);
225
226
  assert.deepStrictEqual(inspect(parser('#a\nb\n#c\n[#d]'), ctx), [['<a class="hashtag" href="/hashtags/a">#a</a>', '<br>', 'b', '<br>', '<a class="hashtag" href="/hashtags/c">#c</a>', '<br>', '<a class="index" href="#index::d">d</a>'], '']);
226
227
  assert.deepStrictEqual(inspect(parser('##a'), ctx), [['##a'], '']);
227
228
  assert.deepStrictEqual(inspect(parser('_#a'), ctx), [['_', '<a class="hashtag" href="/hashtags/a">#a</a>'], '']);