securemark 0.281.4 → 0.283.0

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 (69) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/design.md +5 -9
  3. package/dist/index.js +7354 -7166
  4. package/package.json +2 -2
  5. package/src/combinator/control/manipulation/convert.ts +4 -8
  6. package/src/combinator/control/manipulation/indent.ts +3 -5
  7. package/src/combinator/control/manipulation/scope.ts +6 -3
  8. package/src/combinator/control/manipulation/surround.ts +17 -2
  9. package/src/combinator/data/parser/context.test.ts +6 -6
  10. package/src/combinator/data/parser/context.ts +25 -39
  11. package/src/combinator/data/parser.ts +2 -3
  12. package/src/parser/api/bind.ts +6 -6
  13. package/src/parser/api/parse.test.ts +17 -16
  14. package/src/parser/api/parse.ts +0 -3
  15. package/src/parser/block/blockquote.ts +4 -3
  16. package/src/parser/block/dlist.test.ts +1 -1
  17. package/src/parser/block/dlist.ts +6 -6
  18. package/src/parser/block/extension/aside.ts +4 -3
  19. package/src/parser/block/extension/example.ts +4 -3
  20. package/src/parser/block/extension/table.ts +7 -7
  21. package/src/parser/block/heading.ts +3 -2
  22. package/src/parser/block/ilist.ts +2 -1
  23. package/src/parser/block/olist.ts +4 -3
  24. package/src/parser/block/reply/cite.ts +3 -3
  25. package/src/parser/block/reply/quote.ts +3 -3
  26. package/src/parser/block/sidefence.ts +2 -1
  27. package/src/parser/block/table.ts +9 -9
  28. package/src/parser/block/ulist.ts +6 -5
  29. package/src/parser/block.ts +16 -5
  30. package/src/parser/context.ts +9 -21
  31. package/src/parser/inline/annotation.ts +5 -4
  32. package/src/parser/inline/autolink/email.ts +2 -1
  33. package/src/parser/inline/autolink/url.ts +6 -5
  34. package/src/parser/inline/autolink.ts +2 -2
  35. package/src/parser/inline/bracket.ts +17 -17
  36. package/src/parser/inline/code.test.ts +1 -1
  37. package/src/parser/inline/code.ts +2 -1
  38. package/src/parser/inline/deletion.ts +3 -3
  39. package/src/parser/inline/emphasis.ts +3 -3
  40. package/src/parser/inline/emstrong.ts +3 -3
  41. package/src/parser/inline/extension/index.test.ts +4 -4
  42. package/src/parser/inline/extension/index.ts +18 -6
  43. package/src/parser/inline/extension/indexee.ts +37 -7
  44. package/src/parser/inline/extension/indexer.test.ts +2 -2
  45. package/src/parser/inline/extension/indexer.ts +2 -1
  46. package/src/parser/inline/extension/label.ts +2 -2
  47. package/src/parser/inline/extension/placeholder.ts +4 -4
  48. package/src/parser/inline/html.ts +2 -2
  49. package/src/parser/inline/htmlentity.ts +2 -1
  50. package/src/parser/inline/insertion.ts +3 -3
  51. package/src/parser/inline/link.test.ts +2 -2
  52. package/src/parser/inline/link.ts +7 -7
  53. package/src/parser/inline/mark.test.ts +2 -2
  54. package/src/parser/inline/mark.ts +3 -3
  55. package/src/parser/inline/math.test.ts +3 -3
  56. package/src/parser/inline/math.ts +6 -5
  57. package/src/parser/inline/media.test.ts +1 -1
  58. package/src/parser/inline/media.ts +5 -5
  59. package/src/parser/inline/reference.ts +6 -5
  60. package/src/parser/inline/remark.ts +2 -2
  61. package/src/parser/inline/ruby.ts +3 -3
  62. package/src/parser/inline/strong.ts +3 -3
  63. package/src/parser/inline/template.ts +4 -4
  64. package/src/parser/inline.ts +1 -0
  65. package/src/parser/source/escapable.ts +2 -1
  66. package/src/parser/source/str.ts +3 -2
  67. package/src/parser/source/text.ts +2 -1
  68. package/src/parser/source/unescapable.ts +2 -1
  69. package/src/combinator/data/parser/context/memo.ts +0 -57
@@ -3,6 +3,7 @@ import { union, inits, some, creation, block, line, validate, indent, open, trim
3
3
  import { ulist_, invalid, fillFirstLine } from './ulist';
4
4
  import { olist_ } from './olist';
5
5
  import { inline } from '../inline';
6
+ import { Recursion } from '../context';
6
7
  import { lineable } from '../util';
7
8
  import { visualize, trimBlank } from '../visibility';
8
9
  import { html, defrag } from 'typed-dom/dom';
@@ -13,7 +14,7 @@ export const ilist: IListParser = lazy(() => block(validate(
13
14
 
14
15
  export const ilist_: IListParser = lazy(() => block(fmap(validate(
15
16
  /^[-+*](?:$|\s)/,
16
- some(creation(1, false, union([
17
+ some(creation(0, Recursion.listitem, union([
17
18
  fmap(fallback(
18
19
  inits([
19
20
  line(open(/^[-+*](?:$|\s)/, trim(visualize(trimBlank(lineable(some(inline))))), true)),
@@ -2,9 +2,10 @@ import { OListParser } from '../block';
2
2
  import { union, inits, subsequence, some, creation, block, line, validate, indent, focus, open, match, trim, fallback, lazy, fmap } from '../../combinator';
3
3
  import { ulist_, checkbox, invalid, fillFirstLine } from './ulist';
4
4
  import { ilist_ } from './ilist';
5
- import { inline, indexee, indexer } from '../inline';
5
+ import { inline, indexee, indexer, dataindex } from '../inline';
6
6
  import { lineable } from '../util';
7
7
  import { visualize, trimBlank } from '../visibility';
8
+ import { Recursion } from '../context';
8
9
  import { memoize } from 'spica/memoize';
9
10
  import { html, define, defrag } from 'typed-dom/dom';
10
11
 
@@ -30,7 +31,7 @@ export const olist_: OListParser = lazy(() => block(union([
30
31
  ])));
31
32
 
32
33
  const list = (type: string, form: string): OListParser.ListParser => fmap(
33
- some(creation(1, false, union([
34
+ some(creation(0, Recursion.listitem, union([
34
35
  indexee(fmap(fallback(
35
36
  inits([
36
37
  line(open(heads[form], subsequence([
@@ -39,7 +40,7 @@ const list = (type: string, form: string): OListParser.ListParser => fmap(
39
40
  indent(union([ulist_, olist_, ilist_])),
40
41
  ]),
41
42
  invalid),
42
- ns => [html('li', { 'data-marker': ns.shift() as string || undefined }, defrag(fillFirstLine(ns)))])),
43
+ ns => [html('li', { 'data-index': dataindex(ns), 'data-marker': ns.shift() as string || undefined }, defrag(fillFirstLine(ns)))])),
43
44
  ]))),
44
45
  es => [format(html('ol', es), type, form)]);
45
46
 
@@ -1,10 +1,10 @@
1
1
  import { ReplyParser } from '../../block';
2
- import { union, tails, creation, line, validate, focus, reverse, fmap } from '../../../combinator';
2
+ import { union, tails, line, validate, focus, reverse, fmap } from '../../../combinator';
3
3
  import { anchor } from '../../inline/autolink/anchor';
4
4
  import { str } from '../../source';
5
5
  import { html, define, defrag } from 'typed-dom/dom';
6
6
 
7
- export const cite: ReplyParser.CiteParser = creation(1, false, line(fmap(validate(
7
+ export const cite: ReplyParser.CiteParser = line(fmap(validate(
8
8
  '>>',
9
9
  reverse(tails([
10
10
  str(/^>*(?=>>[^>\s]+\s*$)/),
@@ -23,4 +23,4 @@ export const cite: ReplyParser.CiteParser = creation(1, false, line(fmap(validat
23
23
  define(el, { 'data-depth': `${quotes.length + 1}` }, el.innerText.slice(1)),
24
24
  ])),
25
25
  html('br'),
26
- ])));
26
+ ]));
@@ -1,5 +1,5 @@
1
1
  import { ReplyParser } from '../../block';
2
- import { union, some, creation, block, line, validate, rewrite, convert, lazy, fmap } from '../../../combinator';
2
+ import { union, some, block, line, validate, rewrite, convert, lazy, fmap } from '../../../combinator';
3
3
  import { math } from '../../inline/math';
4
4
  import { autolink } from '../../inline/autolink';
5
5
  import { linebreak, unescsource, str, anyline } from '../../source';
@@ -7,7 +7,7 @@ import { html, defrag } from 'typed-dom/dom';
7
7
 
8
8
  export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
9
9
 
10
- export const quote: ReplyParser.QuoteParser = lazy(() => creation(1, false, block(fmap(validate(
10
+ export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(validate(
11
11
  '>',
12
12
  union([
13
13
  rewrite(
@@ -30,7 +30,7 @@ export const quote: ReplyParser.QuoteParser = lazy(() => creation(1, false, bloc
30
30
  defrag(ns)),
31
31
  html('br'),
32
32
  ]),
33
- false)));
33
+ false));
34
34
 
35
35
  const qblock: ReplyParser.QuoteParser.BlockParser = convert(
36
36
  source => source.replace(/\n$/, '').replace(/(?<=^>+[^\S\n])/mg, '\r'),
@@ -2,6 +2,7 @@ import { SidefenceParser } from '../block';
2
2
  import { union, some, creation, block, focus, rewrite, convert, lazy, fmap } from '../../combinator';
3
3
  import { autolink } from '../autolink';
4
4
  import { contentline } from '../source';
5
+ import { Recursion } from '../context';
5
6
  import { html, define, defrag } from 'typed-dom/dom';
6
7
 
7
8
  export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
@@ -20,7 +21,7 @@ const opener = /^(?=\|\|+(?:$|\s))/;
20
21
  const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
21
22
 
22
23
  const source: SidefenceParser.SourceParser = lazy(() => fmap(
23
- some(creation(1, false, union([
24
+ some(creation(0, Recursion.block, union([
24
25
  focus(
25
26
  /^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/,
26
27
  convert(unindent, source, true)),
@@ -1,5 +1,5 @@
1
1
  import { TableParser } from '../block';
2
- import { union, sequence, some, creation, block, line, validate, focus, rewrite, surround, open, close, trimStart, fallback, lazy, fmap } from '../../combinator';
2
+ import { union, sequence, some, block, line, validate, focus, rewrite, surround, open, close, trimStart, fallback, lazy, fmap } from '../../combinator';
3
3
  import { inline, media, medialink, shortmedia } from '../inline';
4
4
  import { contentline } from '../source';
5
5
  import { trimBlankStart, trimNodeEnd } from '../visibility';
@@ -25,7 +25,7 @@ export const table: TableParser = lazy(() => block(fmap(validate(
25
25
  ]),
26
26
  ])));
27
27
 
28
- const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean): RowParser<P> => creation(1, false, fallback(fmap(
28
+ const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean): RowParser<P> => fallback(fmap(
29
29
  line(surround(/^(?=\|)/, some(union([parser])), /^[|\\]?\s*$/, optional)),
30
30
  es => [html('tr', es)]),
31
31
  rewrite(contentline, ({ source }) => [[
@@ -35,9 +35,9 @@ const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean):
35
35
  'data-invalid-type': 'syntax',
36
36
  'data-invalid-message': 'Missing the start symbol of the table row',
37
37
  }, [html('td', source.replace('\n', ''))])
38
- ], ''])));
38
+ ], '']));
39
39
 
40
- const align: AlignParser = creation(1, false, fmap(open(
40
+ const align: AlignParser = fmap(open(
41
41
  '|',
42
42
  union([
43
43
  focus(/^:-+:/, () => [['center'], '']),
@@ -45,7 +45,7 @@ const align: AlignParser = creation(1, false, fmap(open(
45
45
  focus(/^-+:/, () => [['end'], '']),
46
46
  focus(/^-+/, () => [[''], '']),
47
47
  ])),
48
- ns => [html('td', defrag(ns))]));
48
+ ns => [html('td', defrag(ns))]);
49
49
 
50
50
  const cell: CellParser = surround(
51
51
  /^\|\s*(?=\S)/,
@@ -57,13 +57,13 @@ const cell: CellParser = surround(
57
57
  ])),
58
58
  /^[^|]*/, true);
59
59
 
60
- const head: CellParser.HeadParser = creation(1, false, fmap(
60
+ const head: CellParser.HeadParser = fmap(
61
61
  cell,
62
- ns => [html('th', trimNodeEnd(defrag(ns)))]));
62
+ ns => [html('th', trimNodeEnd(defrag(ns)))]);
63
63
 
64
- const data: CellParser.DataParser = creation(1, false, fmap(
64
+ const data: CellParser.DataParser = fmap(
65
65
  cell,
66
- ns => [html('td', trimNodeEnd(defrag(ns)))]));
66
+ ns => [html('td', trimNodeEnd(defrag(ns)))]);
67
67
 
68
68
  function format(rows: HTMLTableRowElement[]): HTMLTableRowElement[] {
69
69
  const aligns = rows[0].className === 'invalid'
@@ -3,8 +3,9 @@ import { Parser } from '../../combinator/data/parser';
3
3
  import { union, inits, subsequence, some, creation, block, line, validate, indent, focus, rewrite, open, trim, fallback, lazy, fmap } from '../../combinator';
4
4
  import { olist_ } from './olist';
5
5
  import { ilist_ } from './ilist';
6
- import { inline, indexer, indexee } from '../inline';
6
+ import { inline, indexer, indexee, dataindex } from '../inline';
7
7
  import { contentline } from '../source';
8
+ import { Recursion } from '../context';
8
9
  import { lineable } from '../util';
9
10
  import { visualize, trimBlank } from '../visibility';
10
11
  import { unshift } from 'spica/array';
@@ -16,7 +17,7 @@ export const ulist: UListParser = lazy(() => block(validate(
16
17
 
17
18
  export const ulist_: UListParser = lazy(() => block(fmap(validate(
18
19
  /^-(?=$|\s)/,
19
- some(creation(1, false, union([
20
+ some(creation(0, Recursion.listitem, union([
20
21
  indexee(fmap(fallback(
21
22
  inits([
22
23
  line(open(/^-(?:$|\s)/, subsequence([
@@ -26,15 +27,15 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
26
27
  indent(union([ulist_, olist_, ilist_])),
27
28
  ]),
28
29
  invalid),
29
- ns => [html('li', defrag(fillFirstLine(ns)))])),
30
+ ns => [html('li', { 'data-index': dataindex(ns) }, defrag(fillFirstLine(ns)))])),
30
31
  ])))),
31
32
  es => [format(html('ul', es))])));
32
33
 
33
- export const checkbox = creation(1, false, focus(
34
+ export const checkbox = focus(
34
35
  /^\[[xX ]\](?=$|\s)/,
35
36
  ({ source }) => [[
36
37
  html('span', { class: 'checkbox' }, source[1].trimStart() ? '☑' : '☐'),
37
- ], '']));
38
+ ], '']);
38
39
 
39
40
  export const invalid = rewrite(
40
41
  inits([contentline, indent<Parser<string>>(({ source }) => [[source], ''])]),
@@ -1,5 +1,5 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
- import { union, reset, creation, open, fallback, recover } from '../combinator';
2
+ import { union, reset, open, fallback, recover } from '../combinator';
3
3
  import { emptyline } from './source';
4
4
  import { pagebreak } from './block/pagebreak';
5
5
  import { heading } from './block/heading';
@@ -16,6 +16,7 @@ import { blockquote } from './block/blockquote';
16
16
  import { mediablock } from './block/mediablock';
17
17
  import { reply } from './block/reply';
18
18
  import { paragraph } from './block/paragraph';
19
+ import { Recursion } from './context';
19
20
  import { rnd0Z } from 'spica/random';
20
21
  import { html } from 'typed-dom/dom';
21
22
 
@@ -36,9 +37,19 @@ export import MediaBlockParser = BlockParser.MediaBlockParser;
36
37
  export import ReplyParser = BlockParser.ReplyParser;
37
38
  export import ParagraphParser = BlockParser.ParagraphParser;
38
39
 
39
- export const block: BlockParser = creation(0, false,
40
- reset({
41
- resources: { clock: 20000, recursion: 20 + 1 },
40
+ export const block: BlockParser = reset(
41
+ {
42
+ resources: {
43
+ clock: 20000,
44
+ recursions: [
45
+ 10 || Recursion.block,
46
+ 20 || Recursion.blockquote,
47
+ 40 || Recursion.listitem,
48
+ 20 || Recursion.inline,
49
+ 20 || Recursion.bracket,
50
+ 20 || Recursion.terminal,
51
+ ],
52
+ },
42
53
  },
43
54
  error(union([
44
55
  emptyline,
@@ -57,7 +68,7 @@ export const block: BlockParser = creation(0, false,
57
68
  mediablock,
58
69
  reply,
59
70
  paragraph
60
- ]))));
71
+ ])));
61
72
 
62
73
  function error(parser: BlockParser): BlockParser {
63
74
  return recover<BlockParser>(fallback(
@@ -1,23 +1,3 @@
1
- export const enum Syntax {
2
- annotation = 1 << 8,
3
- reference = 1 << 7,
4
- index = 1 << 6,
5
- placeholder = 1 << 5,
6
- ruby = 1 << 4,
7
- link = 1 << 3,
8
- bracket = 1 << 2,
9
- autolink = 1 << 1,
10
- none = 0,
11
- targets = 0
12
- | Syntax.annotation
13
- | Syntax.reference
14
- | Syntax.index
15
- | Syntax.placeholder
16
- | Syntax.ruby
17
- | Syntax.link
18
- | Syntax.bracket,
19
- }
20
-
21
1
  export const enum State {
22
2
  annotation = 1 << 8,
23
3
  reference = 1 << 7,
@@ -40,4 +20,12 @@ export const enum State {
40
20
  | State.autolink,
41
21
  }
42
22
 
43
- export const Margin = 2;
23
+ export const enum Recursion {
24
+ ignore,
25
+ block,
26
+ blockquote,
27
+ listitem,
28
+ inline,
29
+ bracket,
30
+ terminal,
31
+ }
@@ -1,15 +1,16 @@
1
1
  import { AnnotationParser } from '../inline';
2
2
  import { union, some, syntax, creation, constraint, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
- import { Syntax, State } from '../context';
4
+ import { State, Recursion } from '../context';
5
5
  import { trimBlankStart, trimNodeEnd } from '../visibility';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
 
8
- export const annotation: AnnotationParser = lazy(() => creation(surround(
8
+ export const annotation: AnnotationParser = lazy(() => creation(1, Recursion.ignore, surround(
9
9
  '((',
10
10
  constraint(State.annotation, false,
11
- syntax(Syntax.annotation, 6, State.annotation | State.media,
11
+ syntax(6, State.annotation | State.media,
12
12
  trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 2], ['))', 6]])))),
13
13
  '))',
14
14
  false,
15
- ([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest])));
15
+ ([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest],
16
+ undefined, 1)));
@@ -1,11 +1,12 @@
1
1
  import { AutolinkParser } from '../../inline';
2
2
  import { creation, verify, rewrite } from '../../../combinator';
3
3
  import { str } from '../../source';
4
+ import { Recursion } from '../../context';
4
5
  import { html } from 'typed-dom/dom';
5
6
 
6
7
  // https://html.spec.whatwg.org/multipage/input.html
7
8
 
8
- export const email: AutolinkParser.EmailParser = creation(rewrite(verify(
9
+ export const email: AutolinkParser.EmailParser = creation(1, Recursion.ignore, rewrite(verify(
9
10
  str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![0-9a-z])/i),
10
11
  ([source]) => source.length <= 255),
11
12
  ({ source }) => [[html('a', { class: 'email', href: `mailto:${source}` }, source)], '']));
@@ -2,6 +2,7 @@ import { AutolinkParser } from '../../inline';
2
2
  import { union, tails, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
3
3
  import { unsafelink } from '../link';
4
4
  import { linebreak, unescsource, str } from '../../source';
5
+ import { Recursion } from '../../context';
5
6
 
6
7
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
7
8
 
@@ -24,9 +25,9 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
24
25
  unsafelink)),
25
26
  ])));
26
27
 
27
- const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(precedence(2, union([
28
- surround('(', some(union([bracket, unescsource]), ')'), ')', true),
29
- surround('[', some(union([bracket, unescsource]), ']'), ']', true),
30
- surround('{', some(union([bracket, unescsource]), '}'), '}', true),
31
- surround('"', precedence(3, some(unescsource, '"')), '"', true),
28
+ const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, precedence(2, union([
29
+ surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true),
30
+ surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true),
31
+ surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true),
32
+ surround(str('"'), precedence(3, some(unescsource, '"')), str('"'), true),
32
33
  ]))));
@@ -8,13 +8,13 @@ import { hashtag, emoji } from './autolink/hashtag';
8
8
  import { hashnum } from './autolink/hashnum';
9
9
  import { anchor } from './autolink/anchor';
10
10
  import { str } from '../source';
11
- import { Syntax, State } from '../context';
11
+ import { State } from '../context';
12
12
  import { stringify } from '../util';
13
13
 
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(Syntax.autolink, 1, ~State.shortcut,
17
+ syntax(1, ~State.shortcut,
18
18
  union([
19
19
  some(union([lineurl])),
20
20
  fmap(some(union([
@@ -2,46 +2,46 @@ import { BracketParser } from '../inline';
2
2
  import { union, some, syntax, creation, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { Syntax, State } from '../context';
5
+ import { State, Recursion } from '../context';
6
6
  import { unshift, push } from 'spica/array';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
9
  const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
10
10
 
11
11
  export const bracket: BracketParser = lazy(() => union([
12
- surround(str('('), creation(syntax(Syntax.none, 2, State.none, str(index))), str(')')),
13
- surround(str('('), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
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, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
14
14
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
15
- ([as, bs = []], rest) => [unshift(as, bs), rest]),
16
- surround(str('('), creation(syntax(Syntax.none, 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(syntax(Syntax.bracket, 2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
15
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
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, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
18
18
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
19
19
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
20
- surround(str('['), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
20
+ surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
21
21
  undefined,
22
- ([as, bs = []], rest) => [unshift(as, bs), rest]),
23
- surround(str('['), creation(syntax(Syntax.bracket, 2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
22
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
23
+ surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
24
24
  undefined,
25
25
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
26
- surround(str('{'), creation(syntax(Syntax.bracket, 2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
26
+ surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
27
27
  undefined,
28
- ([as, bs = []], rest) => [unshift(as, bs), rest]),
29
- surround(str('{'), creation(syntax(Syntax.bracket, 2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
28
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
29
+ surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
30
30
  undefined,
31
31
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
32
- surround(str('"'), creation(syntax(Syntax.none, 3, State.none, some(inline, '"', [[/^\\?\n/, 4], ['"', 3]]))), str('"'), true,
32
+ surround(str('"'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '"', [[/^\\?\n/, 4], ['"', 3]]))), str('"'), true,
33
33
  undefined,
34
34
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
35
- surround(str('“'), creation(syntax(Syntax.none, 3, State.none, some(inline, '”', [[/^\\?\n/, 4], ['”', 3]]))), str('”'), true,
35
+ surround(str('“'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '”', [[/^\\?\n/, 4], ['”', 3]]))), str('”'), true,
36
36
  undefined,
37
37
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
38
- surround(str('‘'), creation(syntax(Syntax.none, 3, State.none, some(inline, '’', [[/^\\?\n/, 4], ['’', 3]]))), str('’'), true,
38
+ surround(str('‘'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '’', [[/^\\?\n/, 4], ['’', 3]]))), str('’'), true,
39
39
  undefined,
40
40
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
41
- surround(str('「'), creation(syntax(Syntax.none, 3, State.none, some(inline, '」', [[/^\\?\n/, 4], ['」', 3]]))), str('」'), true,
41
+ surround(str('「'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '」', [[/^\\?\n/, 4], ['」', 3]]))), str('」'), true,
42
42
  undefined,
43
43
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
44
- surround(str('『'), creation(syntax(Syntax.none, 3, State.none, some(inline, '』', [[/^\\?\n/, 4], ['』', 3]]))), str('』'), true,
44
+ surround(str('『'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '』', [[/^\\?\n/, 4], ['』', 3]]))), str('』'), true,
45
45
  undefined,
46
46
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
47
47
  ]));
@@ -37,7 +37,7 @@ describe('Unit: parser/inline/code', () => {
37
37
  });
38
38
 
39
39
  it('nest', () => {
40
- assert.deepStrictEqual(inspect(parser('`<wbr>`')), [['<code data-src="`<wbr>`">&lt;wbr&gt;</code>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('`<wbr>`')), [['<code data-src="`&lt;wbr&gt;`">&lt;wbr&gt;</code>'], '']);
41
41
  assert.deepStrictEqual(inspect(parser('`*u*`')), [['<code data-src="`*u*`">*u*</code>'], '']);
42
42
  });
43
43
 
@@ -1,8 +1,9 @@
1
1
  import { CodeParser } from '../inline';
2
2
  import { creation, validate, match } from '../../combinator';
3
+ import { Recursion } from '../context';
3
4
  import { html } from 'typed-dom/dom';
4
5
 
5
- export const code: CodeParser = creation(validate('`', match(
6
+ export const code: CodeParser = creation(1, Recursion.ignore, validate('`', match(
6
7
  /^(`+)(?!`)([^\n]*?[^`\n])\1(?!`)/,
7
8
  ([whole, , body]) => ({ source }) =>
8
9
  [[html('code', { 'data-src': whole }, format(body))], source.slice(whole.length)])));
@@ -2,14 +2,14 @@ import { DeletionParser } from '../inline';
2
2
  import { union, some, syntax, creation, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { Syntax, State } from '../context';
5
+ import { State, Recursion } from '../context';
6
6
  import { blankWith } from '../visibility';
7
7
  import { unshift } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
- export const deletion: DeletionParser = lazy(() => creation(surround(
10
+ export const deletion: DeletionParser = lazy(() => creation(1, Recursion.inline, surround(
11
11
  str('~~', '~'),
12
- syntax(Syntax.none, 1, State.none,
12
+ syntax(1, State.none,
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '~~')),
15
15
  open('\n', some(inline, '~'), true),
@@ -4,14 +4,14 @@ import { inline } from '../inline';
4
4
  import { emstrong } from './emstrong';
5
5
  import { strong } from './strong';
6
6
  import { str } from '../source';
7
- import { Syntax, State } from '../context';
7
+ import { State, Recursion } from '../context';
8
8
  import { startTight, blankWith } from '../visibility';
9
9
  import { unshift } from 'spica/array';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
- export const emphasis: EmphasisParser = lazy(() => creation(surround(
12
+ export const emphasis: EmphasisParser = lazy(() => creation(1, Recursion.inline, surround(
13
13
  str('*', '*'),
14
- syntax(Syntax.none, 1, State.none,
14
+ syntax(1, State.none,
15
15
  startTight(some(union([
16
16
  strong,
17
17
  some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
@@ -5,7 +5,7 @@ import { inline } from '../inline';
5
5
  import { strong } from './strong';
6
6
  import { emphasis } from './emphasis';
7
7
  import { str } from '../source';
8
- import { Syntax, State } from '../context';
8
+ import { State, Recursion } from '../context';
9
9
  import { startTight, blankWith } from '../visibility';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
  import { unshift } from 'spica/array';
@@ -27,9 +27,9 @@ const subemphasis: IntermediateParser<EmphasisParser> = lazy(() => some(union([
27
27
  ])),
28
28
  ])));
29
29
 
30
- export const emstrong: EmStrongParser = lazy(() => creation(surround(
30
+ export const emstrong: EmStrongParser = lazy(() => creation(1, Recursion.inline, surround(
31
31
  str('***'),
32
- syntax(Syntax.none, 1, State.none,
32
+ syntax(1, State.none,
33
33
  startTight(some(union([
34
34
  some(inline, blankWith('*'), [[/^\\?\n/, 9]]),
35
35
  open(some(inline, '*', [[/^\\?\n/, 9]]), inline),
@@ -51,8 +51,8 @@ describe('Unit: parser/inline/extension/index', () => {
51
51
  assert.deepStrictEqual(inspect(parser('[#a\\ ]')), [['<a class="index" href="#index::a">a</a>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
53
53
  assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a__b">a b</a>'], '']);
54
- assert.deepStrictEqual(inspect(parser('[#a\tb]')), [['<a class="index" href="#index::a_b=1eu1tj4">a\tb</a>'], '']);
55
- assert.deepStrictEqual(inspect(parser('[#a_b]')), [['<a class="index" href="#index::a_b=10dxc9b">a_b</a>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('[#a\tb]')), [['<a class="index" href="#index::a_b=33Mw2l">a\tb</a>'], '']);
55
+ assert.deepStrictEqual(inspect(parser('[#a_b]')), [['<a class="index" href="#index::a_b=2H8oCG">a_b</a>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('[#a\\ b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
57
57
  assert.deepStrictEqual(inspect(parser('[#[]]')), [['<a class="index" href="#index::[]">[]</a>'], '']);
58
58
  assert.deepStrictEqual(inspect(parser('[#\\]]')), [['<a class="index" href="#index::]">]</a>'], '']);
@@ -87,8 +87,8 @@ describe('Unit: parser/inline/extension/index', () => {
87
87
  assert.deepStrictEqual(inspect(parser('[#a|*b*]')), [['<a class="index" href="#index::*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
88
88
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
89
89
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b__c">a<span class="indexer" data-index="b__c"></span></a>'], '']);
90
- assert.deepStrictEqual(inspect(parser('[#a|b\tc]')), [['<a class="index" href="#index::b_c=3p5wqt">a<span class="indexer" data-index="b_c=3p5wqt"></span></a>'], '']);
91
- assert.deepStrictEqual(inspect(parser('[#a|b_c]')), [['<a class="index" href="#index::b_c=fvw9e2">a<span class="indexer" data-index="b_c=fvw9e2"></span></a>'], '']);
90
+ assert.deepStrictEqual(inspect(parser('[#a|b\tc]')), [['<a class="index" href="#index::b_c=xeqYk">a<span class="indexer" data-index="b_c=xeqYk"></span></a>'], '']);
91
+ assert.deepStrictEqual(inspect(parser('[#a|b_c]')), [['<a class="index" href="#index::b_c=KUxv5">a<span class="indexer" data-index="b_c=KUxv5"></span></a>'], '']);
92
92
  assert.deepStrictEqual(inspect(parser('[#a|[]]')), [['<a class="index" href="#index::[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
93
93
  assert.deepStrictEqual(inspect(parser('[#a|&copy;]')), [['<a class="index" href="#index::&amp;copy;">a<span class="indexer" data-index="&amp;copy;"></span></a>'], '']);
94
94
  assert.deepStrictEqual(inspect(parser('[#a |b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
@@ -3,16 +3,16 @@ import { union, inits, some, syntax, creation, precedence, constraint, validate,
3
3
  import { inline } from '../../inline';
4
4
  import { indexee, identity } from './indexee';
5
5
  import { txt, str } from '../../source';
6
- import { Syntax, State } from '../../context';
6
+ import { State, Recursion } from '../../context';
7
7
  import { startTight, trimNodeEnd } from '../../visibility';
8
8
  import { html, define, defrag } from 'typed-dom/dom';
9
9
 
10
10
  import IndexParser = ExtensionParser.IndexParser;
11
11
 
12
- export const index: IndexParser = lazy(() => validate('[#', creation(fmap(indexee(surround(
12
+ export const index: IndexParser = lazy(() => validate('[#', creation(1, Recursion.ignore, fmap(indexee(surround(
13
13
  '[#',
14
14
  constraint(State.index, false,
15
- syntax(Syntax.index, 2, State.linkers | State.media,
15
+ syntax(2, State.linkers | State.media,
16
16
  startTight(
17
17
  some(inits([
18
18
  inline,
@@ -20,7 +20,8 @@ export const index: IndexParser = lazy(() => validate('[#', creation(fmap(indexe
20
20
  ]), ']', [[/^\\?\n/, 9], [']', 2]])))),
21
21
  ']',
22
22
  false,
23
- ([, ns], rest) => [[html('a', trimNodeEnd(defrag(ns)))], rest])),
23
+ ([, ns], rest) => [[html('a', { 'data-index': dataindex(ns) }, trimNodeEnd(defrag(ns)))], rest],
24
+ undefined, 1)),
24
25
  ([el]: [HTMLAnchorElement]) => [
25
26
  define(el,
26
27
  {
@@ -30,16 +31,27 @@ export const index: IndexParser = lazy(() => validate('[#', creation(fmap(indexe
30
31
  }),
31
32
  ]))));
32
33
 
33
- export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(fmap(open(
34
+ export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(1, Recursion.ignore, fmap(open(
34
35
  '|',
35
36
  startTight(some(union([bracket, txt]), ']'))),
36
37
  ns => [
37
38
  html('span', { class: 'indexer', 'data-index': identity('index', undefined, ns.join(''))!.slice(7) }),
38
39
  ]))));
39
40
 
40
- const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(union([
41
+ const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
41
42
  surround(str('('), some(union([bracket, txt]), ')'), str(')'), true),
42
43
  surround(str('['), some(union([bracket, txt]), ']'), str(']'), true),
43
44
  surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true),
44
45
  surround(str('"'), precedence(3, some(txt, '"')), str('"'), true),
45
46
  ])));
47
+
48
+ export function dataindex(ns: readonly (string | HTMLElement)[]): string | undefined {
49
+ if (ns.length === 0) return;
50
+ for (let i = ns.length - 1; i >= 0; --i) {
51
+ const node = ns[i];
52
+ if (typeof node === 'string') return;
53
+ if (i === ns.length - 1 && ['UL', 'OL'].includes(node.tagName)) continue;
54
+ if (!node.classList.contains('indexer')) return;
55
+ return node.getAttribute('data-index') ?? undefined;
56
+ }
57
+ }