securemark 0.283.3 → 0.283.5

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 (62) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +142 -107
  3. package/markdown.d.ts +16 -8
  4. package/package.json +1 -1
  5. package/src/combinator/control/manipulation/surround.ts +4 -4
  6. package/src/combinator/data/parser/context/delimiter.ts +20 -20
  7. package/src/combinator/data/parser/context.ts +4 -3
  8. package/src/parser/block/blockquote.ts +1 -1
  9. package/src/parser/block/dlist.ts +6 -6
  10. package/src/parser/block/extension/aside.ts +1 -1
  11. package/src/parser/block/extension/example.ts +2 -2
  12. package/src/parser/block/extension/figure.ts +3 -3
  13. package/src/parser/block/extension/table.ts +5 -5
  14. package/src/parser/block/heading.ts +6 -6
  15. package/src/parser/block/ilist.ts +1 -1
  16. package/src/parser/block/olist.ts +1 -1
  17. package/src/parser/block/paragraph.ts +3 -3
  18. package/src/parser/block/reply.ts +2 -2
  19. package/src/parser/block/sidefence.ts +1 -1
  20. package/src/parser/block/table.ts +4 -4
  21. package/src/parser/block/ulist.ts +1 -1
  22. package/src/parser/block.ts +4 -3
  23. package/src/parser/context.ts +18 -9
  24. package/src/parser/inline/annotation.ts +7 -4
  25. package/src/parser/inline/autolink/account.ts +15 -14
  26. package/src/parser/inline/autolink/anchor.ts +14 -13
  27. package/src/parser/inline/autolink/channel.ts +6 -3
  28. package/src/parser/inline/autolink/email.ts +4 -3
  29. package/src/parser/inline/autolink/hashnum.ts +11 -9
  30. package/src/parser/inline/autolink/hashtag.ts +11 -9
  31. package/src/parser/inline/autolink/url.ts +24 -18
  32. package/src/parser/inline/autolink.ts +4 -5
  33. package/src/parser/inline/bracket.ts +6 -6
  34. package/src/parser/inline/code.ts +1 -1
  35. package/src/parser/inline/deletion.ts +1 -1
  36. package/src/parser/inline/emphasis.ts +1 -1
  37. package/src/parser/inline/emstrong.ts +1 -1
  38. package/src/parser/inline/extension/index.ts +9 -6
  39. package/src/parser/inline/extension/indexer.ts +1 -1
  40. package/src/parser/inline/extension/label.ts +1 -1
  41. package/src/parser/inline/extension/placeholder.ts +1 -1
  42. package/src/parser/inline/html.ts +45 -43
  43. package/src/parser/inline/htmlentity.ts +3 -3
  44. package/src/parser/inline/insertion.ts +1 -1
  45. package/src/parser/inline/link.test.ts +7 -2
  46. package/src/parser/inline/link.ts +11 -15
  47. package/src/parser/inline/mark.ts +1 -1
  48. package/src/parser/inline/math.ts +1 -1
  49. package/src/parser/inline/media.ts +4 -4
  50. package/src/parser/inline/reference.ts +7 -4
  51. package/src/parser/inline/remark.ts +4 -4
  52. package/src/parser/inline/ruby.ts +7 -6
  53. package/src/parser/inline/shortmedia.ts +1 -1
  54. package/src/parser/inline/strong.ts +1 -1
  55. package/src/parser/inline/template.ts +2 -2
  56. package/src/parser/inline.test.ts +1 -0
  57. package/src/parser/segment.ts +3 -2
  58. package/src/parser/source/escapable.ts +2 -2
  59. package/src/parser/source/str.ts +1 -1
  60. package/src/parser/source/text.ts +3 -3
  61. package/src/parser/source/unescapable.ts +4 -2
  62. package/src/parser/visibility.ts +14 -13
package/markdown.d.ts CHANGED
@@ -603,7 +603,7 @@ export namespace MarkdownParser {
603
603
  Block<'reply/cite'>,
604
604
  Parser<HTMLSpanElement | HTMLBRElement, Context, [
605
605
  SourceParser.StrParser,
606
- Parser<HTMLAnchorElement, Context, [
606
+ Parser<string | HTMLAnchorElement, Context, [
607
607
  InlineParser.AutolinkParser.AnchorParser,
608
608
  Parser<HTMLAnchorElement, Context, []>,
609
609
  Parser<HTMLAnchorElement, Context, []>,
@@ -1147,8 +1147,9 @@ export namespace MarkdownParser {
1147
1147
  export interface UrlParser extends
1148
1148
  // https://host
1149
1149
  Inline<'url'>,
1150
- Parser<HTMLAnchorElement, Context, [
1150
+ Parser<string | HTMLAnchorElement, Context, [
1151
1151
  LinkParser.UnsafeLinkParser,
1152
+ Parser<string, Context, []>,
1152
1153
  ]> {
1153
1154
  }
1154
1155
  export namespace UrlParser {
@@ -1156,7 +1157,10 @@ export namespace MarkdownParser {
1156
1157
  Inline<'url/lineurl'>,
1157
1158
  Parser<string | HTMLElement, Context, [
1158
1159
  SourceParser.StrParser,
1159
- InlineParser.LinkParser.UnsafeLinkParser,
1160
+ Parser<string | HTMLElement, Context, [
1161
+ InlineParser.LinkParser.UnsafeLinkParser,
1162
+ Parser<string, Context, []>,
1163
+ ]>,
1160
1164
  ]> {
1161
1165
  }
1162
1166
  export interface BracketParser extends
@@ -1188,7 +1192,7 @@ export namespace MarkdownParser {
1188
1192
  export interface ChannelParser extends
1189
1193
  // @user#tag
1190
1194
  Inline<'channel'>,
1191
- Parser<HTMLAnchorElement, Context, [
1195
+ Parser<string | HTMLAnchorElement, Context, [
1192
1196
  InlineParser.AutolinkParser.AccountParser,
1193
1197
  InlineParser.AutolinkParser.HashtagParser,
1194
1198
  ]> {
@@ -1196,29 +1200,33 @@ export namespace MarkdownParser {
1196
1200
  export interface AccountParser extends
1197
1201
  // @user
1198
1202
  Inline<'account'>,
1199
- Parser<HTMLAnchorElement, Context, [
1203
+ Parser<string | HTMLAnchorElement, Context, [
1200
1204
  LinkParser.UnsafeLinkParser,
1205
+ Parser<string, Context, []>,
1201
1206
  ]> {
1202
1207
  }
1203
1208
  export interface HashtagParser extends
1204
1209
  // #tag
1205
1210
  Inline<'hashtag'>,
1206
- Parser<HTMLAnchorElement, Context, [
1211
+ Parser<string | HTMLAnchorElement, Context, [
1207
1212
  LinkParser.UnsafeLinkParser,
1213
+ Parser<string, Context, []>,
1208
1214
  ]> {
1209
1215
  }
1210
1216
  export interface HashnumParser extends
1211
1217
  // #1
1212
1218
  Inline<'hashnum'>,
1213
- Parser<HTMLAnchorElement, Context, [
1219
+ Parser<string | HTMLAnchorElement, Context, [
1214
1220
  LinkParser.UnsafeLinkParser,
1221
+ Parser<string, Context, []>,
1215
1222
  ]> {
1216
1223
  }
1217
1224
  export interface AnchorParser extends
1218
1225
  // >>1
1219
1226
  Inline<'anchor'>,
1220
- Parser<HTMLAnchorElement, Context, [
1227
+ Parser<string | HTMLAnchorElement, Context, [
1221
1228
  LinkParser.UnsafeLinkParser,
1229
+ Parser<string, Context, []>,
1222
1230
  ]> {
1223
1231
  }
1224
1232
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.283.3",
3
+ "version": "0.283.5",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -59,10 +59,10 @@ export function surround<T>(
59
59
  const { logger = {}, offset = 0 } = context;
60
60
  for (let i = 0; i < source.length - mr_.length; ++i) {
61
61
  if (source[i] !== source[0]) break;
62
- const j = source.length + offset - i;
63
- if (!(j in logger)) continue;
62
+ const pos = source.length + offset - i - 1;
63
+ if (!(pos in logger)) continue;
64
64
  assert(log >>> 2);
65
- if (logger[j] & 1 << (log >>> 2)) return;
65
+ if (logger[pos] & 1 << (log >>> 2)) return;
66
66
  }
67
67
  }
68
68
  const res2 = mr_ !== '' ? parser({ source: mr_, context }) : undefined;
@@ -77,7 +77,7 @@ export function surround<T>(
77
77
  if (rest.length === lmr_.length) return;
78
78
  if (log & 2 && rr === undefined) {
79
79
  const { logger = {}, offset = 0 } = context;
80
- logger[source.length + offset] |= 1 << (log >>> 2);
80
+ logger[source.length + offset - 1] |= 1 << (log >>> 2);
81
81
  }
82
82
  return rr
83
83
  ? f
@@ -33,7 +33,7 @@ export class Delimiters {
33
33
  this.signature);
34
34
  private readonly registry = memoize<(signature: string) => Delimiter[]>(() => []);
35
35
  private readonly delimiters: Delimiter[] = [];
36
- private readonly order: number[] = [];
36
+ private readonly stack: number[] = [];
37
37
  private readonly states: (readonly number[])[] = [];
38
38
  public push(
39
39
  delims: readonly {
@@ -42,14 +42,14 @@ export class Delimiters {
42
42
  readonly precedence: number;
43
43
  }[]
44
44
  ): void {
45
- const { registry, delimiters, order } = this;
46
- // 構文数x優先順位数以下
45
+ const { registry, delimiters, stack } = this;
46
+ // シグネチャ数以下
47
47
  assert(delimiters.length < 100);
48
48
  for (let i = 0; i < delims.length; ++i) {
49
49
  const { signature, matcher, precedence } = delims[i];
50
- const stack = registry(signature);
51
- const index = stack[0]?.index ?? delimiters.length;
52
- if (stack.length === 0 || precedence > delimiters[index].precedence) {
50
+ const memory = registry(signature);
51
+ const index = memory[0]?.index ?? delimiters.length;
52
+ if (memory.length === 0 || precedence > delimiters[index].precedence) {
53
53
  const delimiter: Delimiter = {
54
54
  index,
55
55
  signature,
@@ -58,34 +58,34 @@ export class Delimiters {
58
58
  state: true,
59
59
  };
60
60
  delimiters[index] = delimiter;
61
- stack.push(delimiter);
62
- order.push(index);
61
+ memory.push(delimiter);
62
+ stack.push(index);
63
63
  }
64
64
  else {
65
- order.push(-1);
65
+ stack.push(-1);
66
66
  }
67
67
  // 現状各優先順位は固定
68
- assert(stack.length === 1);
68
+ assert(memory.length === 1);
69
69
  }
70
70
  }
71
71
  public pop(count: number): void {
72
72
  assert(count > 0);
73
- const { registry, delimiters, order } = this;
73
+ const { registry, delimiters, stack } = this;
74
74
  for (let i = 0; i < count; ++i) {
75
- assert(this.order.length > 0);
76
- const index = order.pop()!;
75
+ assert(this.stack.length > 0);
76
+ const index = stack.pop()!;
77
77
  if (index === -1) continue;
78
- const stack = registry(delimiters[index].signature);
79
- assert(stack.length > 0);
80
- if (stack.length === 1) {
78
+ const memory = registry(delimiters[index].signature);
79
+ assert(memory.length > 0);
80
+ if (memory.length === 1) {
81
81
  assert(index === delimiters.length - 1);
82
- assert(stack[0] === delimiters.at(-1));
83
- stack.pop();
82
+ assert(memory[0] === delimiters.at(-1));
83
+ memory.pop();
84
84
  delimiters.pop();
85
85
  }
86
86
  else {
87
- stack.pop();
88
- delimiters[index] = stack.at(-1)!;
87
+ memory.pop();
88
+ delimiters[index] = memory.at(-1)!;
89
89
  }
90
90
  }
91
91
  }
@@ -96,11 +96,12 @@ export function precedence<T>(precedence: number, parser: Parser<T>): Parser<T>
96
96
  assert(precedence >= 0);
97
97
  return ({ source, context }) => {
98
98
  const { delimiters, precedence: p = 0 } = context;
99
- const shift = precedence > p;
99
+ const shift = delimiters && precedence > p;
100
100
  context.precedence = precedence;
101
- shift && delimiters?.shift(precedence);
101
+ // デリミタはシフト後に設定しなければならない
102
+ shift && delimiters.shift(precedence);
102
103
  const result = parser({ source, context });
103
- shift && delimiters?.unshift();
104
+ shift && delimiters.unshift();
104
105
  context.precedence = p;
105
106
  return result;
106
107
  };
@@ -1,8 +1,8 @@
1
1
  import { BlockquoteParser } from '../block';
2
+ import { Recursion } from '../context';
2
3
  import { union, some, creation, block, validate, rewrite, open, convert, lazy, fmap } from '../../combinator';
3
4
  import { autolink } from '../autolink';
4
5
  import { contentline } from '../source';
5
- import { Recursion } from '../context';
6
6
  import { parse } from '../api/parse';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
@@ -1,10 +1,10 @@
1
1
  import { DListParser } from '../block';
2
+ import { State } from '../context';
2
3
  import { union, inits, some, state, block, line, validate, rewrite, open, lazy, fmap } from '../../combinator';
3
4
  import { inline, indexee, indexer, dataindex } from '../inline';
4
5
  import { anyline } from '../source';
5
- import { State } from '../context';
6
6
  import { lineable } from '../util';
7
- import { visualize, trimBlankStart, trimNodeEnd } from '../visibility';
7
+ import { visualize, trimBlank, trimBlankEnd } from '../visibility';
8
8
  import { push } from 'spica/array';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
@@ -19,17 +19,17 @@ export const dlist: DListParser = lazy(() => block(fmap(validate(
19
19
 
20
20
  const term: DListParser.TermParser = line(indexee(fmap(open(
21
21
  /^~[^\S\n]+(?=\S)/,
22
- visualize(trimBlankStart(some(union([indexer, inline])))),
22
+ visualize(trimBlank(some(union([indexer, inline])))),
23
23
  true),
24
- ns => [html('dt', { 'data-index': dataindex(ns) }, trimNodeEnd(defrag(ns)))])));
24
+ ns => [html('dt', { 'data-index': dataindex(ns) }, defrag(ns))])));
25
25
 
26
26
  const desc: DListParser.DescriptionParser = block(fmap(open(
27
27
  /^:[^\S\n]+(?=\S)|/,
28
28
  rewrite(
29
29
  some(anyline, /^[~:][^\S\n]+\S/),
30
- visualize(lineable(some(union([inline]))))),
30
+ visualize(trimBlankEnd(lineable(some(union([inline])))))),
31
31
  true),
32
- ns => [html('dd', trimNodeEnd(defrag(ns)))]),
32
+ ns => [html('dd', defrag(ns))]),
33
33
  false);
34
34
 
35
35
  function fillTrailingDescription(es: HTMLElement[]): HTMLElement[] {
@@ -1,7 +1,7 @@
1
1
  import { ExtensionParser } from '../../block';
2
+ import { Recursion } from '../../context';
2
3
  import { creation, block, validate, fence, fmap } from '../../../combinator';
3
4
  import { identity } from '../../inline/extension/indexee';
4
- import { Recursion } from '../../context';
5
5
  import { parse } from '../../api/parse';
6
6
  import { html } from 'typed-dom/dom';
7
7
 
@@ -1,9 +1,9 @@
1
1
  import { ExtensionParser } from '../../block';
2
+ import { Recursion } from '../../context';
2
3
  import { eval } from '../../../combinator/data/parser';
3
4
  import { creation, block, validate, fence, fmap } from '../../../combinator';
4
- import { parse } from '../../api/parse';
5
5
  import { mathblock } from '../mathblock';
6
- import { Recursion } from '../../context';
6
+ import { parse } from '../../api/parse';
7
7
  import { html } from 'typed-dom/dom';
8
8
 
9
9
  const opener = /^(~{3,})(?:example\/(\S+))?(?!\S)([^\n]*)(?:$|\n)/;
@@ -12,7 +12,7 @@ import { table, segment_ as seg_table } from './table';
12
12
  import { blockquote, segment as seg_blockquote } from '../blockquote';
13
13
  import { placeholder, segment_ as seg_placeholder } from './placeholder';
14
14
  import { inline, media, shortmedia } from '../../inline';
15
- import { visualize, trimBlankStart, trimNodeEnd } from '../../visibility';
15
+ import { visualize, trimBlank } from '../../visibility';
16
16
  import { memoize } from 'spica/memoize';
17
17
  import { html, defrag } from 'typed-dom/dom';
18
18
 
@@ -63,7 +63,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
63
63
  line(shortmedia),
64
64
  ])),
65
65
  emptyline,
66
- block(visualize(trimBlankStart(some(inline)))),
66
+ block(visualize(trimBlank(some(inline)))),
67
67
  ]),
68
68
  ])),
69
69
  ([label, param, content, ...caption]: [HTMLAnchorElement, string, ...HTMLElement[]]) => [
@@ -72,7 +72,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
72
72
  [
73
73
  html('figcaption', [
74
74
  html('span', { class: 'figindex' }),
75
- html('span', { class: 'figtext' }, trimNodeEnd(defrag(caption))),
75
+ html('span', { class: 'figtext' }, defrag(caption)),
76
76
  ]),
77
77
  html('div', [content]),
78
78
  ])
@@ -5,7 +5,7 @@ import { union, subsequence, inits, some, block, line, validate, fence, rewrite,
5
5
  import { inline, medialink, media, shortmedia } from '../../inline';
6
6
  import { str, anyline, emptyline, contentline } from '../../source';
7
7
  import { lineable } from '../../util';
8
- import { visualize, trimBlankStart, trimNodeEnd } from '../../visibility';
8
+ import { visualize, trimBlank, trimBlankEnd } from '../../visibility';
9
9
  import { unshift, splice } from 'spica/array';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
 
@@ -89,10 +89,10 @@ const head: CellParser.HeadParser = block(fmap(open(
89
89
  block(surround(/^[^\n]/, medialink, /^\s*$/)),
90
90
  block(surround(/^[^\n]/, media, /^\s*$/)),
91
91
  block(surround(/^[^\n]/, shortmedia, /^\s*$/)),
92
- open(/^(?:\s*\n|\s)/, visualize(trimBlankStart(some(inline))), true),
92
+ open(/^(?:\s*\n|\s)/, visualize(trimBlank(some(inline))), true),
93
93
  ])),
94
94
  true),
95
- ns => [html('th', attributes(ns.shift()! as string), trimNodeEnd(defrag(ns)))]),
95
+ ns => [html('th', attributes(ns.shift()! as string), defrag(ns))]),
96
96
  false);
97
97
 
98
98
  const data: CellParser.DataParser = block(fmap(open(
@@ -106,10 +106,10 @@ const data: CellParser.DataParser = block(fmap(open(
106
106
  block(surround(/^[^\n]/, medialink, /^\s*$/)),
107
107
  block(surround(/^[^\n]/, media, /^\s*$/)),
108
108
  block(surround(/^[^\n]/, shortmedia, /^\s*$/)),
109
- open(/^(?:\s*\n|\s)/, visualize(lineable(some(inline))), true),
109
+ open(/^(?:\s*\n|\s)/, visualize(trimBlankEnd(lineable(some(inline)))), true),
110
110
  ])),
111
111
  true),
112
- ns => [html('td', attributes(ns.shift()! as string), trimNodeEnd(defrag(ns)))]),
112
+ ns => [html('td', attributes(ns.shift()! as string), defrag(ns))]),
113
113
  false);
114
114
 
115
115
  const dataline: CellParser.DatalineParser = line(
@@ -1,9 +1,9 @@
1
1
  import { HeadingParser } from '../block';
2
+ import { State } from '../context';
2
3
  import { union, some, state, block, line, validate, focus, rewrite, open, fmap } from '../../combinator';
3
4
  import { inline, indexee, indexer, dataindex } from '../inline';
4
5
  import { str } from '../source';
5
- import { State } from '../context';
6
- import { visualize, trimBlankStart, trimNodeEnd } from '../visibility';
6
+ import { visualize, trimBlank } from '../visibility';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
9
  export const segment: HeadingParser.SegmentParser = block(validate('#', focus(
@@ -16,19 +16,19 @@ export const heading: HeadingParser = block(rewrite(segment,
16
16
  line(indexee(fmap(union([
17
17
  open(
18
18
  str(/^##+/),
19
- visualize(trimBlankStart(some(union([indexer, inline])))), true),
19
+ visualize(trimBlank(some(union([indexer, inline])))), true),
20
20
  open(
21
21
  str('#'),
22
22
  state(State.linkers,
23
- visualize(trimBlankStart(some(union([indexer, inline]))))), true),
23
+ visualize(trimBlank(some(union([indexer, inline]))))), true),
24
24
  ]),
25
25
  ([h, ...ns]: [string, ...(HTMLElement | string)[]]) => [
26
26
  h.length <= 6
27
- ? html(`h${h.length as 1}`, { 'data-index': dataindex(ns) }, trimNodeEnd(defrag(ns)))
27
+ ? html(`h${h.length as 1}`, { 'data-index': dataindex(ns) }, defrag(ns))
28
28
  : html(`h6`, {
29
29
  class: 'invalid',
30
30
  'data-invalid-syntax': 'heading',
31
31
  'data-invalid-type': 'syntax',
32
32
  'data-invalid-message': 'Heading level must be up to 6',
33
- }, trimNodeEnd(defrag(ns)))
33
+ }, defrag(ns))
34
34
  ]))))));
@@ -1,9 +1,9 @@
1
1
  import { IListParser } from '../block';
2
+ import { Recursion } from '../context';
2
3
  import { union, inits, some, creation, block, line, validate, indent, open, trim, fallback, lazy, fmap } from '../../combinator';
3
4
  import { ulist_, invalid, fillFirstLine } from './ulist';
4
5
  import { olist_ } from './olist';
5
6
  import { inline } from '../inline';
6
- import { Recursion } from '../context';
7
7
  import { lineable } from '../util';
8
8
  import { visualize, trimBlank } from '../visibility';
9
9
  import { html, defrag } from 'typed-dom/dom';
@@ -1,11 +1,11 @@
1
1
  import { OListParser } from '../block';
2
+ import { Recursion } from '../context';
2
3
  import { union, inits, subsequence, some, creation, block, line, validate, indent, focus, open, match, trim, fallback, lazy, fmap } from '../../combinator';
3
4
  import { ulist_, checkbox, invalid, fillFirstLine } from './ulist';
4
5
  import { ilist_ } from './ilist';
5
6
  import { inline, indexee, indexer, dataindex } from '../inline';
6
7
  import { lineable } from '../util';
7
8
  import { visualize, trimBlank } from '../visibility';
8
- import { Recursion } from '../context';
9
9
  import { memoize } from 'spica/memoize';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
 
@@ -2,9 +2,9 @@ import { ParagraphParser } from '../block';
2
2
  import { union, some, block, fmap } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { lineable } from '../util';
5
- import { visualize, trimNodeEnd } from '../visibility';
5
+ import { visualize, trimBlankEnd } from '../visibility';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
 
8
8
  export const paragraph: ParagraphParser = block(fmap(
9
- visualize(lineable(some(union([inline])))),
10
- ns => [html('p', trimNodeEnd(defrag(ns)))]));
9
+ visualize(trimBlankEnd(lineable(some(union([inline]))))),
10
+ ns => [html('p', defrag(ns))]));
@@ -5,7 +5,7 @@ import { quote, syntax as delimiter } from './reply/quote';
5
5
  import { inline } from '../inline';
6
6
  import { anyline } from '../source';
7
7
  import { lineable } from '../util';
8
- import { visualize, trimNodeEnd } from '../visibility';
8
+ import { visualize, trimBlankNodeEnd } from '../visibility';
9
9
  import { push } from 'spica/array';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
@@ -30,4 +30,4 @@ export const reply: ReplyParser = block(validate('>', fmap(
30
30
  ns => push(ns, [html('br')])),
31
31
  ])),
32
32
  ]),
33
- ns => [html('p', trimNodeEnd(defrag(ns)))])));
33
+ ns => [html('p', trimBlankNodeEnd(defrag(ns)))])));
@@ -1,8 +1,8 @@
1
1
  import { SidefenceParser } from '../block';
2
+ import { Recursion } from '../context';
2
3
  import { union, some, creation, block, focus, rewrite, convert, lazy, fmap } from '../../combinator';
3
4
  import { autolink } from '../autolink';
4
5
  import { contentline } from '../source';
5
- import { Recursion } from '../context';
6
6
  import { html, define, defrag } from 'typed-dom/dom';
7
7
 
8
8
  export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
@@ -2,7 +2,7 @@ import { TableParser } from '../block';
2
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
- import { trimBlankStart, trimNodeEnd } from '../visibility';
5
+ import { trimBlank } from '../visibility';
6
6
  import { duffReduce } from 'spica/duff';
7
7
  import { push } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
@@ -53,17 +53,17 @@ const cell: CellParser = surround(
53
53
  close(medialink, /^\s*(?=\||$)/),
54
54
  close(media, /^\s*(?=\||$)/),
55
55
  close(shortmedia, /^\s*(?=\||$)/),
56
- trimBlankStart(some(inline, /^\|/, [[/^[|\\]?\s*$/, 9]])),
56
+ trimBlank(some(inline, /^\|/, [[/^[|\\]?\s*$/, 9]])),
57
57
  ])),
58
58
  /^[^|]*/, true);
59
59
 
60
60
  const head: CellParser.HeadParser = fmap(
61
61
  cell,
62
- ns => [html('th', trimNodeEnd(defrag(ns)))]);
62
+ ns => [html('th', defrag(ns))]);
63
63
 
64
64
  const data: CellParser.DataParser = fmap(
65
65
  cell,
66
- ns => [html('td', trimNodeEnd(defrag(ns)))]);
66
+ ns => [html('td', defrag(ns))]);
67
67
 
68
68
  function format(rows: HTMLTableRowElement[]): HTMLTableRowElement[] {
69
69
  const aligns = rows[0].className === 'invalid'
@@ -1,11 +1,11 @@
1
1
  import { UListParser } from '../block';
2
2
  import { Parser } from '../../combinator/data/parser';
3
+ import { Recursion } from '../context';
3
4
  import { union, inits, subsequence, some, creation, block, line, validate, indent, focus, rewrite, open, trim, fallback, lazy, fmap } from '../../combinator';
4
5
  import { olist_ } from './olist';
5
6
  import { ilist_ } from './ilist';
6
7
  import { inline, indexer, indexee, dataindex } from '../inline';
7
8
  import { contentline } from '../source';
8
- import { Recursion } from '../context';
9
9
  import { lineable } from '../util';
10
10
  import { visualize, trimBlank } from '../visibility';
11
11
  import { unshift } from 'spica/array';
@@ -1,4 +1,5 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
+ import { Recursion, Command } from './context';
2
3
  import { union, reset, open, fallback, recover } from '../combinator';
3
4
  import { emptyline } from './source';
4
5
  import { pagebreak } from './block/pagebreak';
@@ -16,7 +17,6 @@ import { blockquote } from './block/blockquote';
16
17
  import { mediablock } from './block/mediablock';
17
18
  import { reply } from './block/reply';
18
19
  import { paragraph } from './block/paragraph';
19
- import { Recursion } from './context';
20
20
  import { rnd0Z } from 'spica/random';
21
21
  import { html } from 'typed-dom/dom';
22
22
 
@@ -71,8 +71,9 @@ export const block: BlockParser = reset(
71
71
  ])));
72
72
 
73
73
  function error(parser: BlockParser): BlockParser {
74
+ const reg = new RegExp(String.raw`^${Command.Error}.*\n`)
74
75
  return recover<BlockParser>(fallback(
75
- open('\x07', ({source}) => { throw new Error(source.split('\n', 1)[0]); }),
76
+ open(Command.Error, ({ source }) => { throw new Error(source.split('\n', 1)[0]); }),
76
77
  parser),
77
78
  ({ source, context: { id } }, reason) => [[
78
79
  html('h1',
@@ -89,7 +90,7 @@ function error(parser: BlockParser): BlockParser {
89
90
  translate: 'no',
90
91
  },
91
92
  source
92
- .replace(/^\x07.*\n/, '')
93
+ .replace(reg, '')
93
94
  .slice(0, 1001)
94
95
  .replace(/^(.{997}).{4}$/s, '$1...') || undefined),
95
96
  ], '']);
@@ -1,13 +1,12 @@
1
1
  export const enum State {
2
- annotation = 1 << 8,
3
- reference = 1 << 7,
4
- index = 1 << 6,
5
- label = 1 << 5,
6
- link = 1 << 4,
7
- media = 1 << 3,
8
- mark = 1 << 2,
9
- autolink = 1 << 1,
10
- shortcut = 1 << 0,
2
+ annotation = 1 << 7,
3
+ reference = 1 << 6,
4
+ index = 1 << 5,
5
+ label = 1 << 4,
6
+ link = 1 << 3,
7
+ media = 1 << 2,
8
+ mark = 1 << 1,
9
+ autolink = 1 << 0,
11
10
  none = 0,
12
11
  all = ~0,
13
12
  linkers = 0
@@ -39,3 +38,13 @@ export const enum Backtrack {
39
38
  url = 2 << 2,
40
39
  bracket = 1 << 2,
41
40
  }
41
+
42
+ export const enum Command {
43
+ Error = '\x07',
44
+ Escape = '\x1B',
45
+ Separator = '\x1F',
46
+ }
47
+
48
+ export const CmdRegExp = {
49
+ Escape: /\x1B/g,
50
+ } as const;
@@ -1,16 +1,19 @@
1
1
  import { AnnotationParser } from '../inline';
2
+ import { State, Recursion, Backtrack } from '../context';
2
3
  import { union, some, syntax, creation, constraint, surround, lazy } from '../../combinator';
3
4
  import { inline } from '../inline';
4
- import { State, Recursion, Backtrack } from '../context';
5
- import { trimBlankStart, trimNodeEnd } from '../visibility';
5
+ import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
 
8
8
  export const annotation: AnnotationParser = lazy(() => creation(1, Recursion.ignore, surround(
9
9
  '((',
10
10
  constraint(State.annotation, false,
11
11
  syntax(1, State.annotation | State.media,
12
- trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 1]])))),
12
+ trimBlankStart(some(union([inline]), ')', [['\n', 9], [')', 1]])))),
13
13
  '))',
14
14
  false,
15
- ([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest],
15
+ ([, ns], rest) =>
16
+ trimBlankNodeEnd(ns).length > 0
17
+ ? [[html('sup', { class: 'annotation' }, [html('span', defrag(ns))])], rest]
18
+ : undefined,
16
19
  undefined, 1 | Backtrack.bracket)));
@@ -1,26 +1,27 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { union, tails, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
2
+ import { State } from '../../context';
3
+ import { union, tails, syntax, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
3
4
  import { unsafelink } from '../link';
4
5
  import { str } from '../../source';
5
- import { State } from '../../context';
6
6
  import { define } from 'typed-dom/dom';
7
7
 
8
8
  // https://example/@user must be a user page or a redirect page going there.
9
9
 
10
- export const account: AutolinkParser.AccountParser = lazy(() => fmap(rewrite(
11
- constraint(State.shortcut, false,
10
+ export const account: AutolinkParser.AccountParser = lazy(() => rewrite(
12
11
  open(
13
12
  '@',
14
13
  tails([
15
14
  str(/^[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])?)*\//i),
16
15
  str(/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*/i),
17
- ]))),
18
- convert(
19
- source =>
20
- `[${source}]{ ${
21
- source.includes('/')
22
- ? `https://${source.slice(1).replace('/', '/@')}`
23
- : `/${source}`
24
- } }`,
25
- union([unsafelink]))),
26
- ([el]) => [define(el, { class: 'account' })]));
16
+ ])),
17
+ union([
18
+ constraint(State.autolink, false, syntax(0, State.autolink, fmap(convert(
19
+ source =>
20
+ `[${source}]{ ${source.includes('/')
21
+ ? `https://${source.slice(1).replace('/', '/@')}`
22
+ : `/${source}`
23
+ } }`,
24
+ unsafelink),
25
+ ([el]) => [define(el, { class: 'account' })]))),
26
+ ({ source }) => [[source], ''],
27
+ ])));