securemark 0.284.0 → 0.285.1

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 (40) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +191 -82
  3. package/markdown.d.ts +20 -19
  4. package/package.json +1 -1
  5. package/src/combinator/control/constraint/contract.ts +4 -4
  6. package/src/combinator/control/manipulation/convert.ts +3 -3
  7. package/src/combinator/control/manipulation/indent.ts +3 -3
  8. package/src/combinator/control/manipulation/scope.ts +3 -3
  9. package/src/combinator/control/manipulation/surround.ts +25 -13
  10. package/src/combinator/data/parser/context.ts +1 -1
  11. package/src/combinator/data/parser/some.ts +1 -0
  12. package/src/combinator/data/parser.ts +2 -1
  13. package/src/parser/api/parse.test.ts +14 -14
  14. package/src/parser/context.ts +11 -6
  15. package/src/parser/inline/annotation.ts +2 -2
  16. package/src/parser/inline/autolink/url.ts +14 -7
  17. package/src/parser/inline/bracket.test.ts +2 -2
  18. package/src/parser/inline/deletion.ts +15 -14
  19. package/src/parser/inline/emphasis.ts +2 -2
  20. package/src/parser/inline/emstrong.test.ts +115 -0
  21. package/src/parser/inline/emstrong.ts +71 -37
  22. package/src/parser/inline/extension/index.ts +14 -10
  23. package/src/parser/inline/extension/label.ts +1 -1
  24. package/src/parser/inline/extension/placeholder.ts +2 -2
  25. package/src/parser/inline/html.ts +2 -2
  26. package/src/parser/inline/insertion.ts +15 -14
  27. package/src/parser/inline/italic.test.ts +23 -4
  28. package/src/parser/inline/italic.ts +16 -15
  29. package/src/parser/inline/link.ts +3 -3
  30. package/src/parser/inline/mark.ts +22 -21
  31. package/src/parser/inline/media.ts +10 -6
  32. package/src/parser/inline/reference.ts +2 -2
  33. package/src/parser/inline/ruby.ts +6 -4
  34. package/src/parser/inline/strong.ts +2 -2
  35. package/src/parser/inline/template.ts +7 -8
  36. package/src/parser/inline.test.ts +18 -42
  37. package/src/parser/inline.ts +4 -4
  38. package/src/parser/source/text.ts +0 -4
  39. package/src/parser/util.ts +66 -1
  40. package/src/parser/visibility.ts +22 -19
@@ -1,14 +1,15 @@
1
1
  import { EmStrongParser, EmphasisParser, StrongParser } from '../inline';
2
- import { Recursion } from '../context';
2
+ import { Recursion, Command } from '../context';
3
3
  import { Result, IntermediateParser } from '../../combinator/data/parser';
4
- import { union, creation, precedence, some, surround, open, lazy, bind } from '../../combinator';
4
+ import { union, some, creation, precedence, validate, surround, open, lazy, bind } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
7
  import { emphasis } from './emphasis';
8
8
  import { str } from '../source';
9
- import { startTight, blankWith } from '../visibility';
9
+ import { tightStart, blankWith } from '../visibility';
10
+ import { repeat } from '../util';
10
11
  import { html, defrag } from 'typed-dom/dom';
11
- import { unshift } from 'spica/array';
12
+ import { unshift, push } from 'spica/array';
12
13
 
13
14
  const substrong: IntermediateParser<StrongParser> = lazy(() => some(union([
14
15
  some(inline, blankWith('**')),
@@ -27,36 +28,69 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
27
28
  ])),
28
29
  ])));
29
30
 
30
- export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, surround(
31
- str('***'),
32
- precedence(0,
33
- startTight(some(union([
34
- some(inline, blankWith('*')),
35
- open(some(inline, '*'), inline),
36
- ])))),
37
- str(/^\*{1,3}/), false,
38
- ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
39
- assert(cs.length === 1);
40
- switch (cs[0]) {
41
- case '***':
42
- return [[html('em', [html('strong', defrag(bs))])], rest];
43
- case '**':
44
- return bind<EmphasisParser>(
45
- subemphasis,
46
- (ds, rest) =>
47
- rest.slice(0, 1) === '*'
48
- ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds)))], rest.slice(1)]
49
- : [unshift(['*', html('strong', defrag(bs))], ds), rest])
50
- ({ source: rest, context }) ?? [['*', html('strong', defrag(bs))], rest];
51
- case '*':
52
- return bind<StrongParser>(
53
- substrong,
54
- (ds, rest) =>
55
- rest.slice(0, 2) === '**'
56
- ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds)))], rest.slice(2)]
57
- : [unshift(['**', html('em', defrag(bs))], ds), rest])
58
- ({ source: rest, context }) ?? [['**', html('em', defrag(bs))], rest];
59
- }
60
- assert(false);
61
- },
62
- ([as, bs], rest) => [unshift(as, bs), rest])));
31
+ // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず早く閉じるよう解析しなければならない。
32
+ // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
33
+ export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, validate('***',
34
+ precedence(0, repeat('***', surround(
35
+ '',
36
+ tightStart(some(union([
37
+ some(inline, blankWith('*')),
38
+ open(some(inline, '*'), inline),
39
+ ]))),
40
+ str(/^\*{1,3}/), false,
41
+ ([, bs, cs], rest, context): Result<HTMLElement | string, typeof context> => {
42
+ assert(cs.length === 1);
43
+ switch (cs[0]) {
44
+ case '***':
45
+ return [bs, rest];
46
+ case '**':
47
+ return bind<EmphasisParser>(
48
+ subemphasis,
49
+ (ds, rest) =>
50
+ rest.slice(0, 1) === '*'
51
+ ? [[html('em', unshift([html('strong', defrag(bs))], defrag(ds))), Command.Separator], rest.slice(1)]
52
+ : [push(unshift(['*', html('strong', defrag(bs))], ds), [Command.Separator]), rest])
53
+ ({ source: rest, context }) ?? [['*', html('strong', defrag(bs)), Command.Separator], rest];
54
+ case '*':
55
+ return bind<StrongParser>(
56
+ substrong,
57
+ (ds, rest) =>
58
+ rest.slice(0, 2) === '**'
59
+ ? [[html('strong', unshift([html('em', defrag(bs))], defrag(ds))), Command.Separator], rest.slice(2)]
60
+ : [push(unshift(['**', html('em', defrag(bs))], ds), [Command.Separator]), rest])
61
+ ({ source: rest, context }) ?? [['**', html('em', defrag(bs)), Command.Separator], rest];
62
+ }
63
+ assert(false);
64
+ },
65
+ ([as, bs], rest) => [push(unshift(as, bs), [Command.Escape]), rest]),
66
+ // 3以上の`*`に対してemの適用を保証する
67
+ nodes => [html('em', [html('strong', defrag(nodes))])],
68
+ (acc, rest, prefix, postfix, state) => {
69
+ const nodes = [];
70
+ let i = postfix;
71
+ if (state) while (i > 0) {
72
+ switch (i) {
73
+ case 1:
74
+ acc = [[html('em', acc.flat())]];
75
+ i -= 1;
76
+ break;
77
+ case 2:
78
+ acc = [[html('strong', acc.flat())]];
79
+ i -= 2;
80
+ break;
81
+ default:
82
+ acc = [[html('em', [html('strong', acc.flat())])]];
83
+ i -= 3;
84
+ }
85
+ }
86
+ if (prefix > postfix) {
87
+ nodes.push('*'.repeat(prefix - postfix));
88
+ }
89
+ for (let i = 0; i < acc.length; ++i) {
90
+ nodes.push(...acc[i]);
91
+ }
92
+ if (postfix > 0) {
93
+ rest = rest.slice(postfix);
94
+ }
95
+ return [nodes, rest];
96
+ })))));
@@ -1,10 +1,10 @@
1
1
  import { ExtensionParser } from '../../inline';
2
- import { State, Recursion, Backtrack } from '../../context';
3
- import { union, inits, some, creation, precedence, state, constraint, validate, surround, open, lazy, fmap } from '../../../combinator';
2
+ import { State, Recursion, Backtrack, BacktrackState, Command } from '../../context';
3
+ import { union, inits, some, creation, precedence, state, constraint, validate, verify, surround, open, lazy, fmap } from '../../../combinator';
4
4
  import { inline } from '../../inline';
5
5
  import { indexee, identity } from './indexee';
6
6
  import { txt, str } from '../../source';
7
- import { startTight, trimBlankNodeEnd } from '../../visibility';
7
+ import { tightStart, trimBlankNodeEnd } from '../../visibility';
8
8
  import { html, define, defrag } from 'typed-dom/dom';
9
9
 
10
10
  import IndexParser = ExtensionParser.IndexParser;
@@ -12,7 +12,7 @@ import IndexParser = ExtensionParser.IndexParser;
12
12
  export const index: IndexParser = lazy(() => constraint(State.index, false, creation(1, Recursion.ignore, fmap(indexee(surround(
13
13
  '[#',
14
14
  precedence(1, state(State.linkers | State.media,
15
- startTight(
15
+ tightStart(
16
16
  some(inits([
17
17
  inline,
18
18
  signature,
@@ -23,7 +23,7 @@ export const index: IndexParser = lazy(() => constraint(State.index, false, crea
23
23
  trimBlankNodeEnd(ns).length > 0
24
24
  ? [[html('a', { 'data-index': dataindex(ns) }, defrag(ns))], rest]
25
25
  : undefined,
26
- undefined, 1 | Backtrack.bracket)),
26
+ undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak)),
27
27
  ([el]: [HTMLAnchorElement]) => [
28
28
  define(el,
29
29
  {
@@ -35,16 +35,20 @@ export const index: IndexParser = lazy(() => constraint(State.index, false, crea
35
35
 
36
36
  export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(1, Recursion.ignore, fmap(open(
37
37
  /^\|(?!\\?\s)/,
38
- some(union([bracket, txt]), ']')),
38
+ some(verify(union([bracket, txt]), ns => ns[0] !== Command.Escape), ']')),
39
39
  ns => [
40
40
  html('span', { class: 'indexer', 'data-index': identity('index', undefined, ns.join(''))!.slice(7) }),
41
41
  ]))));
42
42
 
43
43
  const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
44
- surround(str('('), some(union([bracket, txt]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.index),
45
- surround(str('['), some(union([bracket, txt]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.index),
46
- surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.index),
47
- surround(str('"'), precedence(2, some(txt, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.index),
44
+ surround(str('('), some(union([bracket, txt]), ')'), str(')'), true,
45
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
46
+ surround(str('['), some(union([bracket, txt]), ']'), str(']'), true,
47
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
48
+ surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true,
49
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
50
+ surround(str('"'), precedence(2, some(txt, '"')), str('"'), true,
51
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
48
52
  ])));
49
53
 
50
54
  export function dataindex(ns: readonly (string | HTMLElement)[]): string | undefined {
@@ -1,6 +1,6 @@
1
1
  import { ExtensionParser } from '../../inline';
2
2
  import { State, Recursion } from '../../context';
3
- import { union, constraint, creation, surround, clear, fmap } from '../../../combinator';
3
+ import { union, creation, constraint, surround, clear, fmap } from '../../../combinator';
4
4
  import { str } from '../../source';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
@@ -3,7 +3,7 @@ import { Recursion, Backtrack } from '../../context';
3
3
  import { union, some, creation, precedence, surround, lazy } from '../../../combinator';
4
4
  import { inline } from '../../inline';
5
5
  import { str } from '../../source';
6
- import { startTight } from '../../visibility';
6
+ import { tightStart } from '../../visibility';
7
7
  import { unshift } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
@@ -14,7 +14,7 @@ import { html, defrag } from 'typed-dom/dom';
14
14
  export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => creation(1, Recursion.inline, surround(
15
15
  str(/^\[[:^|]/),
16
16
  precedence(1,
17
- startTight(some(union([inline]), ']', [[']', 1]]))),
17
+ tightStart(some(union([inline]), ']', [[']', 1]]))),
18
18
  str(']'), false,
19
19
  ([, bs], rest) => [[
20
20
  html('span', {
@@ -3,7 +3,7 @@ import { Recursion } from '../context';
3
3
  import { union, subsequence, some, creation, precedence, validate, focus, surround, open, match, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
- import { isStartLooseNodes, blankWith } from '../visibility';
6
+ import { isLooseNodeStart, blankWith } from '../visibility';
7
7
  import { memoize } from 'spica/memoize';
8
8
  import { Clock } from 'spica/clock';
9
9
  import { unshift, push, splice } from 'spica/array';
@@ -219,7 +219,7 @@ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: strin
219
219
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag name "${tag}"`, as, bs, cs);
220
220
  if (cs.length === 0) return invalid('tag', `Missing the closing HTML tag "</${tag}>"`, as, bs, cs);
221
221
  if (bs.length === 0) return invalid('content', `Missing the content`, as, bs, cs);
222
- if (!isStartLooseNodes(bs)) return invalid('content', `Missing the visible content in the same line`, as, bs, cs);
222
+ if (!isLooseNodeStart(bs)) return invalid('content', `Missing the visible content in the same line`, as, bs, cs);
223
223
  const attrs = attributes('html', [], attrspecs[tag], as.slice(1, -1));
224
224
  return 'data-invalid-syntax' in attrs
225
225
  ? invalid('attribute', 'Invalid HTML attribute', as, bs, cs)
@@ -1,19 +1,20 @@
1
1
  import { InsertionParser } from '../inline';
2
- import { Recursion } from '../context';
3
- import { union, some, creation, precedence, surround, open, lazy } from '../../combinator';
2
+ import { Recursion, Command } from '../context';
3
+ import { union, some, creation, precedence, validate, surround, open, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { str } from '../source';
6
5
  import { blankWith } from '../visibility';
7
- import { unshift } from 'spica/array';
6
+ import { repeat } from '../util';
7
+ import { push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
- export const insertion: InsertionParser = lazy(() => creation(1, Recursion.inline, surround(
11
- str('++', '+'),
12
- precedence(0,
13
- some(union([
14
- some(inline, blankWith('\n', '++')),
15
- open('\n', some(inline, '+'), true),
16
- ]))),
17
- str('++'), false,
18
- ([, bs], rest) => [[html('ins', defrag(bs))], rest],
19
- ([as, bs], rest) => [unshift(as, bs), rest])));
10
+ export const insertion: InsertionParser = lazy(() => creation(1, Recursion.inline, validate('++',
11
+ precedence(0, repeat('++', surround(
12
+ '',
13
+ some(union([
14
+ some(inline, blankWith('\n', '++')),
15
+ open('\n', some(insertion, '+'), true),
16
+ ])),
17
+ '++', false,
18
+ ([, bs], rest) => [bs, rest],
19
+ ([, bs], rest) => [push(bs, [Command.Escape]), rest]),
20
+ nodes => [html('ins', defrag(nodes))])))));
@@ -15,8 +15,8 @@ describe('Unit: parser/inline/italic', () => {
15
15
  assert.deepStrictEqual(inspect(parser('///a\\ ///')), [['///', 'a'], '\\ ///']);
16
16
  assert.deepStrictEqual(inspect(parser('///a\\\n///')), [['///', 'a'], '\\\n///']);
17
17
  assert.deepStrictEqual(inspect(parser('///a/b')), [['///', 'a', '/', 'b'], '']);
18
- assert.deepStrictEqual(inspect(parser('///a//b')), [['///', 'a', '//', 'b'], '']);
19
- assert.deepStrictEqual(inspect(parser('///a*b///')), [['///', 'a', '*', 'b', '///'], '']);
18
+ assert.deepStrictEqual(inspect(parser('///a//b')), [['///', 'a', '/', '/', 'b'], '']);
19
+ assert.deepStrictEqual(inspect(parser('///a*b///')), [['///', 'a', '*', 'b', '/', '/', '/'], '']);
20
20
  assert.deepStrictEqual(inspect(parser('/// ///')), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('/// a///')), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('/// a ///')), undefined);
@@ -25,8 +25,6 @@ describe('Unit: parser/inline/italic', () => {
25
25
  assert.deepStrictEqual(inspect(parser('///\\ a///')), undefined);
26
26
  assert.deepStrictEqual(inspect(parser('///\\\na///')), undefined);
27
27
  assert.deepStrictEqual(inspect(parser('///<wbr>a///')), undefined);
28
- assert.deepStrictEqual(inspect(parser('////a////')), undefined);
29
- assert.deepStrictEqual(inspect(parser('/////a/////')), undefined);
30
28
  assert.deepStrictEqual(inspect(parser(' ///a///')), undefined);
31
29
  });
32
30
 
@@ -39,8 +37,29 @@ describe('Unit: parser/inline/italic', () => {
39
37
  });
40
38
 
41
39
  it('nest', () => {
40
+ assert.deepStrictEqual(inspect(parser('////a///')), [['/', '<i>a</i>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('////a///b')), [['/', '<i>a</i>'], 'b']);
42
+ assert.deepStrictEqual(inspect(parser('////a////')), [['/', '<i>a</i>', '/'], '']);
43
+ assert.deepStrictEqual(inspect(parser('////a////b')), [['/', '<i>a</i>', '/'], 'b']);
44
+ assert.deepStrictEqual(inspect(parser('/////a///')), [['//', '<i>a</i>'], '']);
45
+ assert.deepStrictEqual(inspect(parser('/////a///b')), [['//', '<i>a</i>'], 'b']);
46
+ assert.deepStrictEqual(inspect(parser('/////a////')), [['//', '<i>a</i>', '/'], '']);
47
+ assert.deepStrictEqual(inspect(parser('/////a////b')), [['//', '<i>a</i>', '/'], 'b']);
48
+ assert.deepStrictEqual(inspect(parser('/////a/////')), [['//', '<i>a</i>', '//'], '']);
49
+ assert.deepStrictEqual(inspect(parser('/////a/////b')), [['//', '<i>a</i>', '//'], 'b']);
50
+ assert.deepStrictEqual(inspect(parser('//////a///')), [['///', '<i>a</i>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('//////a///b')), [['///', '<i>a</i>', 'b'], '']);
52
+ assert.deepStrictEqual(inspect(parser('//////a////')), [['///', '<i>a</i>', '/'], '']);
53
+ assert.deepStrictEqual(inspect(parser('//////a////b')), [['///', '<i>a</i>', '/', 'b'], '']);
54
+ assert.deepStrictEqual(inspect(parser('//////a/////')), [['///', '<i>a</i>', '/', '/'], '']);
55
+ assert.deepStrictEqual(inspect(parser('//////a/////b')), [['///', '<i>a</i>', '/', '/', 'b'], '']);
56
+ assert.deepStrictEqual(inspect(parser('//////a//////')), [['<i><i>a</i></i>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('//////a///b///')), [['<i><i>a</i>b</i>'], '']);
42
58
  assert.deepStrictEqual(inspect(parser('///a ///b//////')), [['<i>a <i>b</i></i>'], '']);
43
59
  assert.deepStrictEqual(inspect(parser('///a\\ ///b//////')), [['<i>a <i>b</i></i>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('///a //////b/////////')), [['<i>a <i><i>b</i></i></i>'], '']);
61
+ assert.deepStrictEqual(inspect(parser('///a ///b///c///')), [['<i>a <i>b</i>c</i>'], '']);
62
+ assert.deepStrictEqual(inspect(parser('///a ///b ///c/////////')), [['<i>a <i>b <i>c</i></i></i>'], '']);
44
63
  assert.deepStrictEqual(inspect(parser('///a&Tab;///b//////')), [['<i>a\t<i>b</i></i>'], '']);
45
64
  assert.deepStrictEqual(inspect(parser('///a<wbr>///b//////')), [['<i>a<wbr><i>b</i></i>'], '']);
46
65
  assert.deepStrictEqual(inspect(parser('///`a`///')), [['<i><code data-src="`a`">a</code></i>'], '']);
@@ -1,21 +1,22 @@
1
1
  import { ItalicParser } from '../inline';
2
- import { Recursion } from '../context';
3
- import { union, some, creation, precedence, surround, open, lazy } from '../../combinator';
2
+ import { Recursion, Command } from '../context';
3
+ import { union, some, creation, precedence, validate, surround, open, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { str } from '../source';
6
- import { startTight, blankWith } from '../visibility';
7
- import { unshift } from 'spica/array';
5
+ import { tightStart, blankWith } from '../visibility';
6
+ import { repeat } from '../util';
7
+ import { push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
11
11
  // ある程度の長さのある文に使うのが望ましい。
12
- export const italic: ItalicParser = lazy(() => creation(1, Recursion.inline, surround(
13
- str('///', '/'),
14
- precedence(0,
15
- startTight(some(union([
16
- some(inline, blankWith('///')),
17
- open(some(inline, '/'), italic),
18
- ])))),
19
- str('///'), false,
20
- ([, bs], rest) => [[html('i', defrag(bs))], rest],
21
- ([as, bs], rest) => [unshift(as, bs), rest])));
12
+ export const italic: ItalicParser = lazy(() => creation(1, Recursion.inline, validate('///',
13
+ precedence(0, repeat('///', surround(
14
+ '',
15
+ tightStart(some(union([
16
+ some(inline, blankWith('///')),
17
+ open(some(inline, '/'), italic),
18
+ ]))),
19
+ '///', false,
20
+ ([, bs], rest) => [bs, rest],
21
+ ([, bs], rest) => [push(bs, [Command.Escape]), rest]),
22
+ nodes => [html('i', defrag(nodes))])))));
@@ -1,7 +1,7 @@
1
1
  import { MarkdownParser } from '../../../markdown';
2
2
  import { LinkParser } from '../inline';
3
- import { State, Recursion, Backtrack } from '../context';
4
- import { union, inits, tails, sequence, some, constraint, creation, precedence, state, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
3
+ import { State, Recursion, Backtrack, BacktrackState } from '../context';
4
+ import { union, inits, tails, sequence, some, creation, precedence, state, constraint, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { linebreak, unescsource, str } from '../source';
@@ -22,7 +22,7 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
22
22
  '[',
23
23
  trimBlankStart(some(union([inline]), ']', [['\n', 9], [']', 1]])),
24
24
  ']',
25
- true, undefined, undefined, 1 | Backtrack.bracket)),
25
+ true, undefined, undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak)),
26
26
  dup(surround(
27
27
  /^{(?![{}])/,
28
28
  inits([uri, some(option)]),
@@ -1,26 +1,27 @@
1
1
  import { MarkParser } from '../inline';
2
- import { State, Recursion } from '../context';
3
- import { union, some, creation, precedence, constraint, surround, open, lazy } from '../../combinator';
2
+ import { State, Recursion, Command } from '../context';
3
+ import { union, some, creation, precedence, constraint, validate, surround, open, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { identity, signature } from './extension/indexee';
6
- import { str } from '../source';
7
- import { startTight, blankWith } from '../visibility';
8
- import { unshift } from 'spica/array';
6
+ import { tightStart, blankWith } from '../visibility';
7
+ import { repeat } from '../util';
8
+ import { push } from 'spica/array';
9
9
  import { html, define, defrag } from 'typed-dom/dom';
10
10
 
11
- export const mark: MarkParser = lazy(() => constraint(State.mark, false, creation(1, Recursion.inline, surround(
12
- str('==', '='),
13
- precedence(0,
14
- startTight(some(union([
15
- some(inline, blankWith('==')),
16
- open(some(inline, '='), mark),
17
- ])))),
18
- str('=='), false,
19
- ([, bs], rest, { id }) => {
20
- const el = html('mark', defrag(bs));
21
- return [[
22
- define(el, { id: identity('mark', id, signature(el)) }),
23
- el.id && html('a', { href: `#${el.id}` }),
24
- ], rest];
25
- },
26
- ([as, bs], rest) => [unshift(as, bs), rest]))));
11
+ export const mark: MarkParser = lazy(() => constraint(State.mark, false, creation(1, Recursion.inline, validate('==',
12
+ precedence(0, repeat('==', surround(
13
+ '',
14
+ tightStart(some(union([
15
+ some(inline, blankWith('==')),
16
+ open(some(inline, '='), mark),
17
+ ]))),
18
+ '==', false,
19
+ ([, bs], rest) => [bs, rest],
20
+ ([, bs], rest) => [push(bs, [Command.Escape]), rest]),
21
+ (nodes, { id }) => {
22
+ const el = html('mark', defrag(nodes));
23
+ define(el, { id: identity('mark', id, signature(el)) });
24
+ return el.id
25
+ ? [el, el.id && html('a', { href: `#${el.id}` })]
26
+ : [el];
27
+ }))))));
@@ -7,7 +7,7 @@ import { unsafehtmlentity } from './htmlentity';
7
7
  import { txt, linebreak, str } from '../source';
8
8
  import { markInvalid } from '../util';
9
9
  import { ReadonlyURL } from 'spica/url';
10
- import { unshift, push } from 'spica/array';
10
+ import { push } from 'spica/array';
11
11
  import { html, define } from 'typed-dom/dom';
12
12
 
13
13
  const optspec = {
@@ -23,7 +23,11 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
23
23
  bind(verify(fmap(tails([
24
24
  dup(surround(
25
25
  '[',
26
- precedence(1, some(union([unsafehtmlentity, bracket, txt]), ']', [['\n', 9]])),
26
+ precedence(1, some(verify(union([
27
+ unsafehtmlentity,
28
+ bracket,
29
+ txt,
30
+ ]), ns => ns[0] !== Command.Escape), ']', [['\n', 9]])),
27
31
  ']',
28
32
  true, undefined, undefined, 1 | Backtrack.media)),
29
33
  dup(surround(
@@ -71,13 +75,13 @@ export const linemedia: MediaParser.LineMediaParser = surround(
71
75
 
72
76
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
73
77
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true,
74
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
78
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
75
79
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true,
76
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
80
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
77
81
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
78
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
82
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
79
83
  surround(str('"'), precedence(2, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
80
- undefined, undefined, 3 | Backtrack.media),
84
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
81
85
  ])));
82
86
 
83
87
  const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
@@ -1,5 +1,5 @@
1
1
  import { ReferenceParser } from '../inline';
2
- import { State, Recursion, Backtrack } from '../context';
2
+ import { State, Recursion, Backtrack, BacktrackState } from '../context';
3
3
  import { union, subsequence, some, creation, precedence, state, constraint, surround, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
@@ -19,7 +19,7 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
19
19
  trimBlankNodeEnd(ns).length > 0
20
20
  ? [[html('sup', attributes(ns), [html('span', defrag(ns))])], rest]
21
21
  : undefined,
22
- undefined, 1 | Backtrack.bracket))));
22
+ undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak))));
23
23
 
24
24
  // Chicago-Style
25
25
  const abbr: ReferenceParser.AbbrParser = creation(1, Recursion.ignore, surround(
@@ -4,7 +4,7 @@ import { eval, exec } from '../../combinator/data/parser';
4
4
  import { sequence, creation, surround, lazy, fmap, bind } from '../../combinator';
5
5
  import { unsafehtmlentity } from './htmlentity';
6
6
  import { text as txt, str } from '../source';
7
- import { isStartTightNodes } from '../visibility';
7
+ import { isTightNodeStart } from '../visibility';
8
8
  import { unshift, push } from 'spica/array';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
@@ -13,7 +13,7 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
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
15
  ns && ns.at(-1) === '' && ns.pop();
16
- return ns && isStartTightNodes(ns) ? [[ns], rest] : undefined;
16
+ return ns && isTightNodeStart(ns) ? [[ns], rest] : undefined;
17
17
  }),
18
18
  bind(surround('(', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
19
19
  const ns = eval(text({ source, context }), [undefined])[0];
@@ -26,7 +26,8 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
26
26
  return [
27
27
  html('ruby', attributes(texts, rubies), defrag(texts
28
28
  .reduce((acc, _, i) =>
29
- push(acc, unshift([texts[i]],
29
+ push(acc, unshift(
30
+ [texts[i]],
30
31
  i < rubies.length && rubies[i]
31
32
  ? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
32
33
  : [html('rt')]))
@@ -36,7 +37,8 @@ export const ruby: RubyParser = lazy(() => creation(1, Recursion.ignore, fmap(
36
37
  return [
37
38
  html('ruby', attributes(texts, rubies), defrag([...texts[0]]
38
39
  .reduce((acc, _, i, texts) =>
39
- push(acc, unshift([texts[i]],
40
+ push(acc, unshift(
41
+ [texts[i]],
40
42
  i < rubies.length && rubies[i]
41
43
  ? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
42
44
  : [html('rt')]))
@@ -4,14 +4,14 @@ import { union, some, creation, precedence, surround, open, lazy } from '../../c
4
4
  import { inline } from '../inline';
5
5
  import { emstrong } from './emstrong';
6
6
  import { str } from '../source';
7
- import { startTight, blankWith } from '../visibility';
7
+ import { tightStart, blankWith } from '../visibility';
8
8
  import { unshift } from 'spica/array';
9
9
  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
13
  precedence(0,
14
- startTight(some(union([
14
+ tightStart(some(union([
15
15
  some(inline, blankWith('**')),
16
16
  open(some(inline, '*'), union([
17
17
  emstrong,
@@ -1,13 +1,12 @@
1
1
  import { TemplateParser } from '../inline';
2
- import { Recursion, Backtrack } from '../context';
3
- import { union, some, creation, precedence, surround, lazy } from '../../combinator';
2
+ import { Recursion, Backtrack, Command } from '../context';
3
+ import { union, some, creation, precedence, verify, surround, lazy } from '../../combinator';
4
4
  import { escsource, str } from '../source';
5
- import { unshift } from 'spica/array';
6
5
  import { html } from 'typed-dom/dom';
7
6
 
8
7
  export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore, surround(
9
8
  '{{',
10
- precedence(1, some(union([bracket, escsource]), '}')),
9
+ precedence(1, some(verify(union([bracket, escsource]), ns => ns[0] !== Command.Escape), '}')),
11
10
  '}}',
12
11
  true,
13
12
  ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('')}}}`)], rest],
@@ -15,11 +14,11 @@ export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore,
15
14
 
16
15
  const bracket: TemplateParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
17
16
  surround(str('('), some(union([bracket, escsource]), ')'), str(')'), true,
18
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
17
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
19
18
  surround(str('['), some(union([bracket, escsource]), ']'), str(']'), true,
20
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
19
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
21
20
  surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true,
22
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
21
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
23
22
  surround(str('"'), precedence(2, some(escsource, /^["\n]/)), str('"'), true,
24
- undefined, undefined, 3 | Backtrack.template),
23
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
25
24
  ])));