securemark 0.300.0 → 0.300.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 +4 -0
  2. package/dist/index.js +197 -113
  3. package/package.json +1 -1
  4. package/src/api/bind.ts +2 -2
  5. package/src/api/parse.ts +2 -2
  6. package/src/combinator/control/inits.ts +13 -4
  7. package/src/combinator/control/sequence.ts +3 -1
  8. package/src/combinator/control/state.ts +1 -10
  9. package/src/combinator/control/union.ts +16 -3
  10. package/src/combinator/parser.ts +18 -8
  11. package/src/combinator/process/fence.ts +3 -3
  12. package/src/combinator/process/surround.ts +2 -0
  13. package/src/parser/block/codeblock.test.ts +0 -2
  14. package/src/parser/block/codeblock.ts +3 -3
  15. package/src/parser/block/extension/aside.test.ts +0 -1
  16. package/src/parser/block/extension/aside.ts +1 -1
  17. package/src/parser/block/extension/example.test.ts +0 -2
  18. package/src/parser/block/extension/example.ts +1 -1
  19. package/src/parser/block/extension/figure.test.ts +0 -4
  20. package/src/parser/block/extension/figure.ts +1 -1
  21. package/src/parser/block/extension/message.test.ts +0 -1
  22. package/src/parser/block/extension/message.ts +1 -1
  23. package/src/parser/block/extension/placeholder.ts +3 -3
  24. package/src/parser/block/extension/table.test.ts +0 -1
  25. package/src/parser/block/extension/table.ts +3 -3
  26. package/src/parser/block/mathblock.test.ts +0 -2
  27. package/src/parser/block/mathblock.ts +3 -3
  28. package/src/parser/context.ts +9 -12
  29. package/src/parser/document.ts +1 -1
  30. package/src/parser/inline/autolink/url.ts +4 -4
  31. package/src/parser/inline/math.ts +1 -1
  32. package/src/parser/inline/media.ts +4 -4
  33. package/src/parser/inline/ruby.ts +45 -8
  34. package/src/parser/inline/template.ts +4 -4
  35. package/src/parser/source/escapable.ts +0 -1
  36. package/src/parser/source/text.ts +14 -43
  37. package/src/parser/source/unescapable.ts +0 -1
  38. package/src/parser/source/whitespace.ts +36 -0
  39. package/src/parser/source.ts +1 -0
  40. package/src/parser/visibility.ts +2 -1
@@ -3,7 +3,7 @@ import { Input, Backtrack } from '../context';
3
3
  import { Parser, Result, List, Node } from '../../combinator/parser';
4
4
  import { union, inits, always, backtrack, surround, setBacktrack, dup, lazy, bind } from '../../combinator';
5
5
  import { unsafehtmlentity } from './htmlentity';
6
- import { txt } from '../source';
6
+ import { txt, isWhitespace } from '../source';
7
7
  import { isNonblankNodeStart } from '../visibility';
8
8
  import { unwrap } from '../util';
9
9
  import { html, defrag } from 'typed-dom/dom';
@@ -63,8 +63,6 @@ export const ruby: RubyParser = lazy(() => backtrack(bind(
63
63
  }
64
64
  })));
65
65
 
66
- const delimiter = /[$"`\[\](){}<>()[]{}|]|\\?\r?\n/y;
67
-
68
66
  interface Memory {
69
67
  position: number;
70
68
  state: boolean;
@@ -72,7 +70,7 @@ interface Memory {
72
70
  }
73
71
  const text: RubyParser.TextParser = always<Parser<string, Input<Memory>>>([
74
72
  (input, output) => {
75
- input.sequential = true;
73
+ input.whitespace = true;
76
74
  input.memory = {
77
75
  position: 0,
78
76
  state: false,
@@ -83,7 +81,7 @@ const text: RubyParser.TextParser = always<Parser<string, Input<Memory>>>([
83
81
  () => loop,
84
82
  (input, output) => {
85
83
  const { memory } = input;
86
- input.sequential = false;
84
+ input.whitespace = false;
87
85
  return memory.state || memory.nodes.last!.value.trimStart() !== ''
88
86
  ? output.import(memory.nodes)
89
87
  : undefined;
@@ -94,10 +92,9 @@ const loop: Result<string, Input<Memory>> = [
94
92
  const { source, memory } = input;
95
93
  for (let { position } = input; ; position = input.position) {
96
94
  if (position === source.length) return Result.skip;
97
- delimiter.lastIndex = position;
98
- if (delimiter.test(source)) return Result.skip;
95
+ if (isDelimiter(source, position)) return Result.skip;
99
96
  assert(source[position] !== '\n');
100
- if (source[position].trimStart() !== '') break;
97
+ if (!isWhitespace(source[position])) break;
101
98
  memory.state ||= memory.nodes.last!.value.trimStart() !== '';
102
99
  memory.nodes.push(new Node(''));
103
100
  input.position += 1;
@@ -124,3 +121,43 @@ function* zip<N extends Node<unknown>>(a: List<N>, b: List<N>): Iterable<[N | un
124
121
  yield [ra.value, rb.value];
125
122
  }
126
123
  }
124
+
125
+ function isDelimiter(source: string, position: number): boolean {
126
+ switch (source[position]) {
127
+ case '$':
128
+ case '"':
129
+ case '`':
130
+ case '[':
131
+ case ']':
132
+ case '(':
133
+ case ')':
134
+ case '{':
135
+ case '}':
136
+ case '<':
137
+ case '>':
138
+ case '(':
139
+ case ')':
140
+ case '[':
141
+ case ']':
142
+ case '{':
143
+ case '}':
144
+ case '|':
145
+ return true;
146
+ case '\\':
147
+ switch (source[position + 1]) {
148
+ case '\r':
149
+ return source[position + 2] === '\n';
150
+ case '\n':
151
+ return true;
152
+ default:
153
+ return false;
154
+ }
155
+ case '\r':
156
+ return source[position + 1] === '\n';
157
+ case '\n':
158
+ return true;
159
+ default:
160
+ return false;
161
+ }
162
+ assert(false);
163
+ }
@@ -25,15 +25,15 @@ export const template: TemplateParser = lazy(() => backtrack(surround(
25
25
  input.source.slice(input.position - input.range, input.position)))))));
26
26
 
27
27
  const bracket: TemplateParser.BracketParser = lazy(() => union([
28
- surround(str('('), recursion(Recursion.terminal, some(union([bracket, escsource]), ')')), str(')'),
28
+ surround(str('('), recursion(Recursion.bracket, some(union([bracket, escsource]), ')')), str(')'),
29
29
  true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
30
- surround(str('['), recursion(Recursion.terminal, some(union([bracket, escsource]), ']')), str(']'),
30
+ surround(str('['), recursion(Recursion.bracket, some(union([bracket, escsource]), ']')), str(']'),
31
31
  true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
32
- surround(str('{'), recursion(Recursion.terminal, some(union([bracket, escsource]), '}')), str('}'),
32
+ surround(str('{'), recursion(Recursion.bracket, some(union([bracket, escsource]), '}')), str('}'),
33
33
  true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
34
34
  surround(
35
35
  str('"'),
36
- precedence(2, recursion(Recursion.terminal, some(escsource, /["\n]/y, [['"', 2], ['\n', 3]]))),
36
+ precedence(2, recursion(Recursion.bracket, some(escsource, /["\n]/y, [['"', 2], ['\n', 3]]))),
37
37
  str('"'),
38
38
  true, [], undefined, ([as, bs], _, output) => bs && output.import(as.import(bs as List<Node<string>>))),
39
39
  ]));
@@ -34,7 +34,6 @@ export const escsource: EscapableSourceParser = (input, output) => {
34
34
  return output.append(new Node(html('br'), Flag.blank));
35
35
  default:
36
36
  assert(char !== '\n');
37
- if (input.sequential) return output.append(new Node(char));
38
37
  let i = seek(source, position);
39
38
  assert(i > position);
40
39
  i -= position;
@@ -3,6 +3,7 @@ import { Result, Node } from '../../combinator/parser';
3
3
  import { union, spend } from '../../combinator';
4
4
  import { State, Command } from '../context';
5
5
  import { Flag } from '../node';
6
+ import { isWhitespace } from './whitespace';
6
7
  import { html } from 'typed-dom/dom';
7
8
 
8
9
  export const nonWhitespace = /[^ \t ]/g;
@@ -35,14 +36,13 @@ export const text: TextParser = (input, output) => {
35
36
  return output.append(new Node(html('br'), Flag.blank));
36
37
  default:
37
38
  assert(char !== '\n');
38
- if (input.sequential) return output.append(new Node(char));
39
39
  nonWhitespace.lastIndex = position + 1;
40
40
  const s = canSkip(source, position);
41
41
  let i = s
42
42
  ? nonWhitespace.test(source)
43
43
  ? nonWhitespace.lastIndex - 1
44
44
  : source.length
45
- : next(source, position, state);
45
+ : next(source, position, input.whitespace, state);
46
46
  assert(i > position);
47
47
  const lineend = 0
48
48
  || s && i === source.length
@@ -68,28 +68,15 @@ export function canSkip(source: string, position: number): boolean {
68
68
  if (position + 1 === source.length) return true;
69
69
  return isWhitespace(source[position + 1], true);
70
70
  }
71
- function isWhitespace(char: string, linebreak: boolean): boolean {
72
- switch (char) {
73
- case ' ':
74
- case '\t':
75
- case ' ':
76
- return true;
77
- case '\r':
78
- case '\n':
79
- return linebreak;
80
- default:
81
- return false;
82
- }
83
- }
84
71
 
85
- function next(source: string, position: number, state: number): number {
86
- let index= seek(source, position, state);
72
+ function next(source: string, position: number, space: boolean, state: number): number {
73
+ let index= seek(source, position, space, state);
87
74
  assert(index > position);
88
75
  if (index === source.length) return index;
89
76
  const char = source[index];
90
77
  switch (char) {
91
78
  case '%':
92
- assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true));
79
+ assert(source.startsWith('%]', index) && isWhitespace(source[index - 1]));
93
80
  index += index - 1 > position
94
81
  ? -1
95
82
  : 0;
@@ -167,7 +154,7 @@ export function isAlphanumeric(char: string): boolean {
167
154
  return 'A' <= char && char <= 'Z';
168
155
  }
169
156
 
170
- function seek(source: string, position: number, state: number): number {
157
+ function seek(source: string, position: number, space: boolean, state: number): number {
171
158
  for (let i = position + 1; i < source.length; ++i) {
172
159
  const char = source[i];
173
160
  switch (char) {
@@ -208,7 +195,7 @@ function seek(source: string, position: number, state: number): number {
208
195
  if (source[i + 1] === char && source[i + 2] === char) return i;
209
196
  continue;
210
197
  case '%':
211
- if (source[i + 1] === ']' && isWhitespace(source[i - 1], true)) return i;
198
+ if (source[i + 1] === ']' && isWhitespace(source[i - 1])) return i;
212
199
  continue;
213
200
  case ':':
214
201
  if (source[i + 1] === '/' && source[i + 2] === '/') return i;
@@ -216,30 +203,14 @@ function seek(source: string, position: number, state: number): number {
216
203
  case '&':
217
204
  if (source[i + 1] !== ' ') return i;
218
205
  continue;
219
- case ' ':
220
- case '\t':
221
- case ' ':
222
- if (i + 1 === source.length) return i;
223
- switch (source[i + 1]) {
224
- case ' ':
225
- case '\t':
226
- case '\r':
227
- case '\n':
228
- case ' ':
229
- return i;
230
- case '\\':
231
- if (i + 2 === source.length) return i;
232
- switch (source[i + 2]) {
233
- case ' ':
234
- case '\t':
235
- case '\r':
236
- case '\n':
237
- case ' ':
238
- return i;
239
- }
240
- }
241
- continue;
242
206
  default:
207
+ if (!isWhitespace(char)) continue;
208
+ if (space) return i;
209
+ if (i + 1 === source.length) return i;
210
+ if (isWhitespace(source[i + 1])) return i;
211
+ if (source[i + 1] !== '\\') continue;
212
+ if (i + 2 === source.length) return i;
213
+ if (isWhitespace(source[i + 2])) return i;
243
214
  continue;
244
215
  }
245
216
  assert(false);
@@ -24,7 +24,6 @@ export const unescsource: UnescapableSourceParser = (input, output) => {
24
24
  return output.append(new Node(html('br'), Flag.blank));
25
25
  default:
26
26
  assert(char !== '\n');
27
- if (input.sequential) return output.append(new Node(char));
28
27
  nonWhitespace.lastIndex = position + 1;
29
28
  let i = canSkip(source, position)
30
29
  ? nonWhitespace.test(source)
@@ -0,0 +1,36 @@
1
+ // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5Cp%7BWhite_Space%7D&g=&i=
2
+ // https://en.wikipedia.org/wiki/Whitespace_character
3
+ // https://en.wikipedia.org/wiki/Newline
4
+ export function isWhitespace(char: string, linebreak: boolean = true): boolean {
5
+ switch (char) {
6
+ case '\u0009':
7
+ case '\u000B':
8
+ case '\u000C':
9
+ case '\u0020':
10
+ case '\u0085':
11
+ case '\u00A0':
12
+ case '\u1680':
13
+ case '\u2000':
14
+ case '\u2001':
15
+ case '\u2002':
16
+ case '\u2003':
17
+ case '\u2004':
18
+ case '\u2005':
19
+ case '\u2006':
20
+ case '\u2007':
21
+ case '\u2008':
22
+ case '\u2009':
23
+ case '\u200A':
24
+ case '\u2028':
25
+ case '\u2029':
26
+ case '\u202F':
27
+ case '\u205F':
28
+ case '\u3000':
29
+ return true;
30
+ case '\u000A':
31
+ case '\u000D':
32
+ return linebreak;
33
+ default:
34
+ return false;
35
+ }
36
+ }
@@ -15,4 +15,5 @@ export { text, txt } from './source/text';
15
15
  export { escsource } from './source/escapable';
16
16
  export { unescsource } from './source/unescapable';
17
17
  export { str, strs } from './source/str';
18
+ export { isWhitespace } from './source/whitespace';
18
19
  export { contentline, emptyline, emptysegment, anyline } from './source/line';
@@ -3,6 +3,7 @@ import { Input, Command } from './context';
3
3
  import { Flag } from './node';
4
4
  import { always, fmap } from '../combinator';
5
5
  import { invisibleBlankHTMLEntityNames } from '../api/normalize';
6
+ import { isWhitespace } from './source';
6
7
 
7
8
  namespace blank {
8
9
  export const line = new RegExp(
@@ -102,7 +103,7 @@ function isNonblank({ value: node, flags }: Node<HTMLElement | string>, strpos?:
102
103
  case '\n':
103
104
  return false;
104
105
  default:
105
- return str.trimStart() !== '';
106
+ return !isWhitespace(str.trimStart());
106
107
  }
107
108
  }
108
109