securemark 0.293.3 → 0.293.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 (36) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +125 -141
  3. package/package.json +1 -1
  4. package/src/combinator/control/manipulation/surround.ts +2 -2
  5. package/src/combinator/data/parser/context.test.ts +10 -9
  6. package/src/combinator/data/parser/context.ts +2 -1
  7. package/src/combinator/data/parser.ts +0 -3
  8. package/src/parser/api/bind.ts +3 -3
  9. package/src/parser/api/normalize.ts +1 -3
  10. package/src/parser/api/parse.ts +1 -1
  11. package/src/parser/block/dlist.test.ts +1 -1
  12. package/src/parser/block/heading.test.ts +1 -0
  13. package/src/parser/block/olist.test.ts +1 -0
  14. package/src/parser/block/reply/quote.ts +6 -6
  15. package/src/parser/block/reply.ts +3 -2
  16. package/src/parser/block/ulist.test.ts +1 -0
  17. package/src/parser/header.test.ts +3 -1
  18. package/src/parser/header.ts +2 -2
  19. package/src/parser/inline/emphasis.test.ts +1 -0
  20. package/src/parser/inline/html.test.ts +3 -3
  21. package/src/parser/inline/html.ts +9 -9
  22. package/src/parser/inline/italic.test.ts +1 -0
  23. package/src/parser/inline/link.test.ts +10 -8
  24. package/src/parser/inline/link.ts +17 -17
  25. package/src/parser/inline/mark.test.ts +1 -0
  26. package/src/parser/inline/media.test.ts +6 -7
  27. package/src/parser/inline/media.ts +3 -3
  28. package/src/parser/inline/remark.test.ts +3 -1
  29. package/src/parser/inline/strong.test.ts +1 -0
  30. package/src/parser/source/escapable.test.ts +1 -0
  31. package/src/parser/source/escapable.ts +3 -11
  32. package/src/parser/source/text.test.ts +5 -4
  33. package/src/parser/source/text.ts +90 -94
  34. package/src/parser/source/unescapable.test.ts +1 -0
  35. package/src/parser/source/unescapable.ts +5 -8
  36. package/src/parser/util.ts +0 -19
@@ -15,6 +15,7 @@ describe('Unit: parser/source/text', () => {
15
15
  it('basic', () => {
16
16
  assert.deepStrictEqual(inspect(parser('a'), ctx), [['a'], '']);
17
17
  assert.deepStrictEqual(inspect(parser('ab'), ctx), [['ab'], '']);
18
+ assert.deepStrictEqual(inspect(parser('a b c'), ctx), [['a b c'], '']);
18
19
  assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09あいAZaz'], '']);
19
20
  assert.deepStrictEqual(inspect(parser('a\nb'), ctx), [['a', '<br>', 'b'], '']);
20
21
  });
@@ -39,8 +40,8 @@ describe('Unit: parser/source/text', () => {
39
40
  assert.deepStrictEqual(inspect(parser(' '), ctx), [[], '']);
40
41
  assert.deepStrictEqual(inspect(parser(' \n'), ctx), [['<br>'], '']);
41
42
  assert.deepStrictEqual(inspect(parser(' \n'), ctx), [['<br>'], '']);
42
- assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
43
- assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [['<br>'], '']);
43
+ assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [[' ', '<br>'], '']);
44
+ assert.deepStrictEqual(inspect(parser(' \\\n'), ctx), [[' ', ' ', '<br>'], '']);
44
45
  assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' a'], '']);
45
46
  assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
46
47
  assert.deepStrictEqual(inspect(parser(' a'), ctx), [[' ', ' a'], '']);
@@ -48,8 +49,8 @@ describe('Unit: parser/source/text', () => {
48
49
  assert.deepStrictEqual(inspect(parser('a '), ctx), [['a'], '']);
49
50
  assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
50
51
  assert.deepStrictEqual(inspect(parser('a \n'), ctx), [['a', '<br>'], '']);
51
- assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
52
- assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', '<br>'], '']);
52
+ assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', ' ', '<br>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('a \\\n'), ctx), [['a', ' ', '<br>'], '']);
53
54
  assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a b'], '']);
54
55
  assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
55
56
  assert.deepStrictEqual(inspect(parser('a b'), ctx), [['a', ' b'], '']);
@@ -4,7 +4,7 @@ import { union, consume, focus } from '../../combinator';
4
4
  import { html } from 'typed-dom/dom';
5
5
 
6
6
  //const delimiter = /(?=[\\!@#$&"`\[\](){}<>()[]{}*%|\r\n]|([+~=])\1|\/{3}|\s(?:\\?(?:$|\s)|[$%])|:\/\/)/g;
7
- export const nonWhitespace = /[\S\r\n]/g;
7
+ export const nonWhitespace = /[^ \t ]/g;
8
8
 
9
9
  export const text: TextParser = input => {
10
10
  const { context } = input;
@@ -38,29 +38,24 @@ export const text: TextParser = input => {
38
38
  assert(char !== '\n');
39
39
  if (context.sequential) return [[char]];
40
40
  nonWhitespace.lastIndex = position + 1;
41
- const b = isBlank(source, position);
42
- let i = b
43
- ? source[position + 1] === '\n'
44
- ? position + 1
45
- : nonWhitespace.test(source)
46
- ? nonWhitespace.lastIndex - 1
47
- : source.length
41
+ const s = canSkip(source, position);
42
+ let i = s
43
+ ? nonWhitespace.test(source)
44
+ ? nonWhitespace.lastIndex - 1
45
+ : source.length
48
46
  : next(source, position);
49
47
  assert(i > position);
50
48
  const lineend = 0
51
- || b && i === source.length
52
- || b && source[i] === '\n'
53
- || b && source[i] === '\\' && source[i + 1] === '\n';
49
+ || s && i === source.length
50
+ || s && source[i] === '\n';
54
51
  i -= position;
55
- i = lineend ? i : i - +b || 1;
52
+ i = lineend ? i : i - +s || 1;
56
53
  consume(i - 1, context);
57
54
  context.position += i - 1;
58
55
  const linestart = position === 0 || source[position - 1] === '\n';
59
- i = linestart && b && i >= 3 ? i - 3 : 0;
60
- i += position;
61
- return i === context.position || b && !linestart || lineend
56
+ return position === context.position || s && !linestart || lineend
62
57
  ? [[]]
63
- : [[source.slice(i, context.position)]];
58
+ : [[source.slice(position, context.position)]];
64
59
  }
65
60
  };
66
61
 
@@ -72,6 +67,26 @@ export const linebreak: LinebreakParser = focus(/[\r\n]/y, union([
72
67
  text,
73
68
  ])) as LinebreakParser;
74
69
 
70
+ export function canSkip(source: string, position: number): boolean {
71
+ assert(position < source.length);
72
+ if (!isWhitespace(source[position], false)) return false;
73
+ if (position + 1 === source.length) return true;
74
+ return isWhitespace(source[position + 1], true);
75
+ }
76
+ function isWhitespace(char: string, linebreak: boolean): boolean {
77
+ switch (char) {
78
+ case ' ':
79
+ case '\t':
80
+ case ' ':
81
+ return true;
82
+ case '\r':
83
+ case '\n':
84
+ return linebreak;
85
+ default:
86
+ return false;
87
+ }
88
+ }
89
+
75
90
  export function next(source: string, position: number, delimiter?: RegExp): number {
76
91
  let index: number;
77
92
  if (delimiter) {
@@ -86,8 +101,24 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
86
101
  assert(index > position);
87
102
  const char = source[index];
88
103
  switch (char) {
104
+ case '$':
105
+ case '%':
106
+ case '*':
107
+ case '+':
108
+ case '~':
109
+ case '=':
110
+ case '/':
111
+ index = backToWhitespace(source, position, index);
112
+ break;
113
+ case '[':
114
+ index = source[index + 1] === '|'
115
+ ? backToWhitespace(source, position, index)
116
+ : index;
117
+ break;
89
118
  case ':':
90
- index = backToUrlHead(source, position, index);
119
+ index = source.startsWith('//', index + 1)
120
+ ? backToUrlHead(source, position, index)
121
+ : index;
91
122
  break;
92
123
  case '@':
93
124
  index = backToEmailHead(source, position, index);
@@ -96,39 +127,39 @@ export function next(source: string, position: number, delimiter?: RegExp): numb
96
127
  assert(index > position);
97
128
  return index;
98
129
  }
130
+ export function backToWhitespace(source: string, position: number, index: number): number {
131
+ const prev = index - 1;
132
+ return prev > position && /\s/.test(source[prev])
133
+ ? prev
134
+ : index;
135
+ }
99
136
  export function backToUrlHead(source: string, position: number, index: number): number {
100
137
  const delim = index;
101
138
  let state = false;
102
- let offset = 0;
103
- for (let i = index; --i > position;) {
104
- index = i;
139
+ for (let i = index - 1; i >= position; --i) {
105
140
  const char = source[i];
106
141
  if (state) switch (char) {
107
142
  case '.':
108
143
  case '+':
109
144
  case '-':
110
145
  state = false;
111
- offset = 1;
112
146
  continue;
113
147
  }
114
148
  if (isAlphanumeric(char)) {
115
149
  state = true;
116
- offset = 0;
150
+ index = i;
117
151
  continue;
118
152
  }
119
153
  break;
120
154
  }
121
- if (index === position + 1 && offset === 0 && isAlphanumeric(source[index - 1])) {
122
- return delim;
123
- }
124
- return index + offset;
155
+ return index === position
156
+ ? delim
157
+ : index;
125
158
  }
126
159
  export function backToEmailHead(source: string, position: number, index: number): number {
127
160
  const delim = index;
128
161
  let state = false;
129
- let offset = 0;
130
- for (let i = index; --i > position;) {
131
- index = i;
162
+ for (let i = index - 1; i >= position; --i) {
132
163
  const char = source[i];
133
164
  if (state) switch (char) {
134
165
  case '_':
@@ -136,22 +167,19 @@ export function backToEmailHead(source: string, position: number, index: number)
136
167
  case '+':
137
168
  case '-':
138
169
  state = false;
139
- offset = 1;
140
170
  continue;
141
171
  }
142
172
  if (isAlphanumeric(char)) {
143
173
  state = true;
144
- offset = 0;
174
+ index = i;
145
175
  continue;
146
176
  }
147
177
  break;
148
178
  }
149
- if (index === position + 1 && offset === 0 && isAlphanumeric(source[index - 1])) {
150
- return delim;
151
- }
152
- return index + offset;
179
+ return index === position
180
+ ? delim
181
+ : index;
153
182
  }
154
-
155
183
  function isAlphanumeric(char: string): boolean {
156
184
  assert(char.length === 1);
157
185
  if (char < '0' || '\x7F' < char) return false;
@@ -195,8 +223,6 @@ function isAlphanumeric(char: string): boolean {
195
223
  // }
196
224
  //};
197
225
 
198
- const delimiter = /\s(?:\\?(?:$|\s)|[$%])/y;
199
-
200
226
  function seek(source: string, position: number): number {
201
227
  for (let i = position + 1; i < source.length; ++i) {
202
228
  const fst = source[i];
@@ -225,7 +251,6 @@ function seek(source: string, position: number): number {
225
251
  case '{':
226
252
  case '}':
227
253
  case '*':
228
- case '%':
229
254
  case '|':
230
255
  case '\r':
231
256
  case '\n':
@@ -238,68 +263,39 @@ function seek(source: string, position: number): number {
238
263
  case '/':
239
264
  if (source[i + 1] === fst && source[i + 2] === fst) return i;
240
265
  continue;
266
+ case '%':
267
+ if (source[i + 1] === ']') return i;
268
+ continue;
241
269
  case ':':
242
270
  if (source[i + 1] === '/' && source[i + 2] === '/') return i;
243
271
  continue;
244
- //case ' ':
245
- //case '\t':
246
- //case ' ':
247
- // if (i + 1 === source.length) return i;
248
- // switch (source[i + 1]) {
249
- // case ' ':
250
- // case '\t':
251
- // case '\r':
252
- // case '\n':
253
- // case ' ':
254
- // case '$':
255
- // case '%':
256
- // return i;
257
- // case '\\':
258
- // if (i + 2 === source.length) return i;
259
- // switch (source[i + 2]) {
260
- // case ' ':
261
- // case '\t':
262
- // case '\r':
263
- // case '\n':
264
- // case ' ':
265
- // return i;
266
- // }
267
- // }
268
- // continue;
272
+ case ' ':
273
+ case '\t':
274
+ case ' ':
275
+ if (i + 1 === source.length) return i;
276
+ switch (source[i + 1]) {
277
+ case ' ':
278
+ case '\t':
279
+ case '\r':
280
+ case '\n':
281
+ case ' ':
282
+ return i;
283
+ case '\\':
284
+ if (i + 2 === source.length) return i;
285
+ switch (source[i + 2]) {
286
+ case ' ':
287
+ case '\t':
288
+ case '\r':
289
+ case '\n':
290
+ case ' ':
291
+ return i;
292
+ }
293
+ }
294
+ continue;
269
295
  default:
270
- delimiter.lastIndex = i;
271
- if (delimiter.test(source)) return i;
272
296
  continue;
273
297
  }
274
298
  assert(false);
275
299
  }
276
300
  return source.length;
277
301
  }
278
-
279
- const blank = /\s(?:$|\s|\\\n)/y;
280
- export function isBlank(source: string, position: number): boolean {
281
- blank.lastIndex = position;
282
- return blank.test(source);
283
- assert(position < source.length);
284
- if (!isWhitespace(source[position])) return false;
285
- if (position + 1 === source.length) return true;
286
- const snd = source[position + 1];
287
- if (isWhitespace(snd)) return true;
288
- if (position + 2 === source.length) return false;
289
- if (snd === '\\' && source[position + 2] === '\n') return true;
290
- return false;
291
- }
292
- const whitespace = /\s/;
293
- export function isWhitespace(char: string): boolean {
294
- whitespace;
295
- switch (char) {
296
- case ' ':
297
- case '\t':
298
- case '\r':
299
- case '\n':
300
- case ' ':
301
- return true
302
- default:
303
- return false;
304
- }
305
- }
@@ -15,6 +15,7 @@ describe('Unit: parser/source/unescapable', () => {
15
15
  it('basic', () => {
16
16
  assert.deepStrictEqual(inspect(parser('a'), ctx), [['a'], '']);
17
17
  assert.deepStrictEqual(inspect(parser('ab'), ctx), [['ab'], '']);
18
+ assert.deepStrictEqual(inspect(parser('a b c'), ctx), [['a', ' b', ' c'], '']);
18
19
  assert.deepStrictEqual(inspect(parser('09あいAZaz'), ctx), [['09', 'あいAZaz'], '']);
19
20
  });
20
21
 
@@ -1,7 +1,7 @@
1
1
  import { UnescapableSourceParser } from '../source';
2
2
  import { Command } from '../context';
3
3
  import { consume } from '../../combinator';
4
- import { nonWhitespace, isBlank, next } from './text';
4
+ import { nonWhitespace, canSkip, next } from './text';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
7
7
  export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
@@ -28,13 +28,10 @@ export const unescsource: UnescapableSourceParser = ({ context }) => {
28
28
  assert(char !== '\n');
29
29
  if (context.sequential) return [[char]];
30
30
  nonWhitespace.lastIndex = position + 1;
31
- const b = isBlank(source, position);
32
- let i = b
33
- ? source[position + 1] === '\n'
34
- ? position + 1
35
- : nonWhitespace.test(source)
36
- ? nonWhitespace.lastIndex - 1
37
- : source.length
31
+ let i = canSkip(source, position)
32
+ ? nonWhitespace.test(source)
33
+ ? nonWhitespace.lastIndex - 1
34
+ : source.length
38
35
  : next(source, position, delimiter);
39
36
  assert(i > position);
40
37
  i -= position;
@@ -2,27 +2,8 @@ import { min } from 'spica/alias';
2
2
  import { MarkdownParser } from '../../markdown';
3
3
  import { Command } from './context';
4
4
  import { Parser, Result, Ctx, Node, Context, eval, failsafe } from '../combinator/data/parser';
5
- import { convert } from '../combinator';
6
5
  import { define } from 'typed-dom/dom';
7
6
 
8
- export function linearize<P extends Parser<HTMLElement | string>>(parser: P, trim?: 0 | 1 | -1): P;
9
- export function linearize<N extends HTMLElement | string>(parser: Parser<N>, trim = 0): Parser<N> {
10
- return convert(
11
- source => `${
12
- trim === 0
13
- ? source
14
- : trim > 0
15
- ? source.at(-1) === '\n'
16
- ? source
17
- : source + '\n'
18
- : source.at(-1) === '\n'
19
- ? source.slice(0, -1)
20
- : source
21
- }`,
22
- parser,
23
- trim === 0);
24
- }
25
-
26
7
  export function repeat<P extends Parser<HTMLElement | string, MarkdownParser.Context>>(symbol: string, parser: P, cons: (nodes: Node<P>[], context: Context<P>) => Node<P>[], termination?: (acc: Node<P>[], context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | Node<P>>): P;
27
8
  export function repeat<N extends HTMLElement | string>(symbol: string, parser: Parser<N>, cons: (nodes: N[], context: MarkdownParser.Context) => N[], termination: (acc: N[], context: Ctx, prefix: number, postfix: number, state: boolean) => Result<string | N, MarkdownParser.Context> = (nodes, context, prefix, postfix) => {
28
9
  const acc = [];