securemark 0.270.2 → 0.272.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.270.2",
3
+ "version": "0.272.0",
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",
@@ -28,35 +28,35 @@
28
28
  "LICENSE"
29
29
  ],
30
30
  "devDependencies": {
31
- "@types/dompurify": "3.0.0",
31
+ "@types/dompurify": "3.0.2",
32
32
  "@types/jquery": "3.5.16",
33
33
  "@types/mathjax": "0.0.37",
34
34
  "@types/mocha": "10.0.1",
35
35
  "@types/power-assert": "1.5.8",
36
36
  "@types/prismjs": "1.26.0",
37
- "@typescript-eslint/parser": "^5.55.0",
37
+ "@typescript-eslint/parser": "^5.59.0",
38
38
  "babel-loader": "^9.1.2",
39
39
  "babel-plugin-unassert": "^3.2.0",
40
- "concurrently": "^7.6.0",
41
- "eslint": "^8.36.0",
40
+ "concurrently": "^8.0.1",
41
+ "eslint": "^8.39.0",
42
42
  "eslint-plugin-redos": "^4.4.5",
43
- "eslint-webpack-plugin": "^4.0.0",
44
- "glob": "^8.1.0",
45
- "karma": "^6.4.1",
46
- "karma-chrome-launcher": "^3.1.1",
43
+ "eslint-webpack-plugin": "^4.0.1",
44
+ "glob": "^10.2.1",
45
+ "karma": "^6.4.2",
46
+ "karma-chrome-launcher": "^3.2.0",
47
47
  "karma-coverage": "^2.2.0",
48
48
  "karma-firefox-launcher": "^2.1.2",
49
49
  "karma-mocha": "^2.0.1",
50
50
  "karma-power-assert": "^1.0.0",
51
51
  "mocha": "^10.2.0",
52
- "npm-check-updates": "^16.7.12",
53
- "semver": "^7.3.8",
54
- "spica": "0.0.719",
52
+ "npm-check-updates": "^16.10.9",
53
+ "semver": "^7.5.0",
54
+ "spica": "0.0.721",
55
55
  "ts-loader": "^9.4.2",
56
- "typed-dom": "^0.0.317",
57
- "typescript": "4.9.5",
58
- "webpack": "^5.76.1",
59
- "webpack-cli": "^5.0.1",
56
+ "typed-dom": "^0.0.330",
57
+ "typescript": "5.0.4",
58
+ "webpack": "^5.80.0",
59
+ "webpack-cli": "^5.0.2",
60
60
  "webpack-merge": "^5.8.0"
61
61
  },
62
62
  "scripts": {
@@ -214,15 +214,15 @@ describe('Unit: parser/api/bind', () => {
214
214
  cfgs.footnotes.references?.outerHTML,
215
215
  html('ol', [
216
216
  html('li', { id: 'reference::def:1' }, [
217
- html('span', { id: 'note::1' }, '1'),
217
+ html('span', '1'),
218
218
  html('sup', [html('a', { href: '#reference::ref:1' }, '^1')]),
219
219
  ]),
220
220
  html('li', { id: 'reference::def:2' }, [
221
- html('span', { id: 'note::2' }, '2'),
221
+ html('span', '2'),
222
222
  html('sup', [html('a', { href: '#reference::ref:2' }, '^2')]),
223
223
  ]),
224
224
  html('li', { id: 'reference::def:3' }, [
225
- html('span', { id: 'note::3' }, '3'),
225
+ html('span', '3'),
226
226
  html('sup', [html('a', { href: '#reference::ref:3' }, '^3')]),
227
227
  ]),
228
228
  ]).outerHTML);
@@ -124,7 +124,7 @@ describe('Unit: parser/api/parse', () => {
124
124
  '<p><a class="index" href="#index::a">a</a></p>',
125
125
  '<figure data-type="math" data-label="$-a" data-group="$" data-number="1" id="label:$-a"><figcaption><span class="figindex">(1)</span><span class="figtext"></span></figcaption><div><div class="math" translate="no">$$\n$$</div></div></figure>',
126
126
  '<p><a class="label" data-label="$-a" href="#label:$-a">(1)</a></p>',
127
- '<p><sup class="annotation" id="annotation::ref:1" title="a"><span hidden="">a</span><a href="#annotation::def:1">*1</a></sup></p>',
127
+ '<p><sup class="annotation" id="annotation::ref:1" title="a"><span hidden="">a</span><a href="#annotation::def:a">*1</a></sup></p>',
128
128
  '<p><a class="url" href="https://source/x/a" target="_blank">a</a></p>',
129
129
  '<p><a class="url" href="https://source/a" target="_blank">/a</a></p>',
130
130
  '<p><a class="url" href="/z/a">^/a</a></p>',
@@ -135,7 +135,7 @@ describe('Unit: parser/api/parse', () => {
135
135
  '<p><a href="https://source/x/a" target="_blank"><img class="media" data-src="https://source/x/a" alt=""></a></p>',
136
136
  '<p><a href="/z/a" target="_blank"><img class="media" data-src="/z/a" alt=""></a></p>',
137
137
  '<p><a href="https://source/a" target="_blank"><img class="media" data-src="https://source/a" alt=""></a></p>',
138
- '<ol class="annotations"><li id="annotation::def:1" data-marker="*1"><span id="note::a">a</span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
138
+ '<ol class="annotations"><li id="annotation::def:a" data-marker="*1"><span>a</span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
139
139
  ]);
140
140
  assert.deepStrictEqual(
141
141
  [...parse([
@@ -207,12 +207,12 @@ describe('Unit: parser/api/parse', () => {
207
207
  [...parse('$-a\n$$\n$$\n\n(($-a[[b]][[c_d_]]))', { footnotes }).children].map(el => el.outerHTML),
208
208
  [
209
209
  '<figure data-type="math" data-label="$-a" data-group="$" data-number="1" id="label:$-a"><figcaption><span class="figindex">(1)</span><span class="figtext"></span></figcaption><div><div class="math" translate="no">$$\n$$</div></div></figure>',
210
- '<p><sup class="annotation" id="annotation::ref:1" title="(1)"><span hidden=""><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" id="reference::ref:1" title="b"><span hidden="">b</span><a href="#reference::def:1">[1]</a></sup><sup class="reference" id="reference::ref:2" title="cd"><span hidden="">c<em>d</em></span><a href="#reference::def:2">[2]</a></sup></span><a href="#annotation::def:1">*1</a></sup></p>',
211
- '<ol class="annotations"><li id="annotation::def:1" data-marker="*1"><span id="note::(1)"><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" id="reference::ref:1" title="b"><span hidden="">b</span><a href="#reference::def:1">[1]</a></sup><sup class="reference" id="reference::ref:2" title="cd"><span hidden="">c<em>d</em></span><a href="#reference::def:2">[2]</a></sup></span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
210
+ '<p><sup class="annotation" id="annotation::ref:1" title="(1)"><span hidden=""><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference"><span>b</span></sup><sup class="reference"><span>c<em>d</em></span></sup></span><a href="#annotation::def:(1)">*1</a></sup></p>',
211
+ '<ol class="annotations"><li id="annotation::def:(1)" data-marker="*1"><span><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" id="reference::ref:1" title="b"><span hidden="">b</span><a href="#reference::def:b">[1]</a></sup><sup class="reference" id="reference::ref:2" title="cd"><span hidden="">c<em>d</em></span><a href="#reference::def:cd">[2]</a></sup></span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
212
212
  ]);
213
213
  assert.deepStrictEqual(
214
214
  footnotes.references.outerHTML,
215
- '<ol><li id="reference::def:1"><span id="note::b">b</span><sup><a href="#reference::ref:1">^1</a></sup></li><li id="reference::def:2"><span id="note::cd">c<em>d</em></span><sup><a href="#reference::ref:2">^2</a></sup></li></ol>');
215
+ '<ol><li id="reference::def:b"><span>b</span><sup><a href="#reference::ref:1">^1</a></sup></li><li id="reference::def:cd"><span>c<em>d</em></span><sup><a href="#reference::ref:2">^2</a></sup></li></ol>');
216
216
  });
217
217
 
218
218
  it('normalize', () => {
@@ -1,6 +1,6 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { block, validate, fence, fmap } from '../../../combinator';
3
- import { identity, text } from '../../inline/extension/indexee';
3
+ import { identity, index } from '../../inline/extension/indexee';
4
4
  import { parse } from '../../api/parse';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
@@ -34,9 +34,9 @@ export const aside: ExtensionParser.AsideParser = block(validate('~~~', fmap(
34
34
  'data-invalid-type': 'content',
35
35
  'data-invalid-message': 'Missing the title at the first line',
36
36
  }, `${opener}${body}${closer}`)];
37
- assert(identity(context.id, text(heading)));
37
+ assert(identity(context.id, index(heading)));
38
38
  return [
39
- html('aside', { id: identity(context.id, text(heading)), class: 'aside' }, [
39
+ html('aside', { id: identity(context.id, index(heading)), class: 'aside' }, [
40
40
  document,
41
41
  html('h2', 'References'),
42
42
  references,
@@ -296,7 +296,7 @@ describe('Unit: parser/block/extension/table', () => {
296
296
  html('tbody', [
297
297
  html('tr', [
298
298
  html('th', { class: 'highlight' }, '1.1'),
299
- html('td', { class: 'highlight', highlight: 'h' }, '1.2'),
299
+ html('td', '1.2'),
300
300
  ]),
301
301
  ]),
302
302
  html('tfoot'),
@@ -307,7 +307,7 @@ describe('Unit: parser/block/extension/table', () => {
307
307
  html('thead'),
308
308
  html('tbody', [
309
309
  html('tr', [
310
- html('td', { class: 'highlight', highlight: 'h' }, '1.1'),
310
+ html('td', '1.1'),
311
311
  html('th', { class: 'highlight' }, '1.2'),
312
312
  ]),
313
313
  ]),
@@ -319,18 +319,40 @@ describe('Unit: parser/block/extension/table', () => {
319
319
  html('thead', [
320
320
  html('tr', [html('th', { class: 'highlight' }, '1.1')]),
321
321
  ]),
322
+ html('tbody', [
323
+ html('tr', [html('td', '2.1')]),
324
+ ]),
325
+ html('tfoot'),
326
+ ]).outerHTML], '']);
327
+ assert.deepStrictEqual(
328
+ inspect(parser('~~~table\n#! 1.1\n-\n:!+ 2.1\n~~~')),
329
+ [[html('table', [
330
+ html('thead', [
331
+ html('tr', [html('th', { class: 'highlight' }, '1.1')]),
332
+ ]),
333
+ html('tbody', [
334
+ html('tr', [html('td', { class: 'invalid' }, '2.1')]),
335
+ ]),
336
+ html('tfoot'),
337
+ ]).outerHTML], '']);
338
+ assert.deepStrictEqual(
339
+ inspect(parser('~~~table\n#!+ 1.1\n-\n: 2.1\n~~~')),
340
+ [[html('table', [
341
+ html('thead', [
342
+ html('tr', [html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.1')]),
343
+ ]),
322
344
  html('tbody', [
323
345
  html('tr', [html('td', { class: 'highlight', highlight: 'v' }, '2.1')]),
324
346
  ]),
325
347
  html('tfoot'),
326
348
  ]).outerHTML], '']);
327
349
  assert.deepStrictEqual(
328
- inspect(parser('~~~table\n#! 1.1\n# 1.2\n: 1.3\n~~~')),
350
+ inspect(parser('~~~table\n#!+ 1.1\n# 1.2\n: 1.3\n~~~')),
329
351
  [[html('table', [
330
352
  html('thead'),
331
353
  html('tbody', [
332
354
  html('tr', [
333
- html('th', { class: 'highlight' }, '1.1'),
355
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.1'),
334
356
  html('th', '1.2'),
335
357
  html('td', '1.3'),
336
358
  ]),
@@ -338,23 +360,23 @@ describe('Unit: parser/block/extension/table', () => {
338
360
  html('tfoot'),
339
361
  ]).outerHTML], '']);
340
362
  assert.deepStrictEqual(
341
- inspect(parser('~~~table\n: 1.1\n# 1.2\n#! 1.3\n~~~')),
363
+ inspect(parser('~~~table\n: 1.1\n# 1.2\n#!+ 1.3\n~~~')),
342
364
  [[html('table', [
343
365
  html('thead'),
344
366
  html('tbody', [
345
367
  html('tr', [
346
368
  html('td', '1.1'),
347
369
  html('th', '1.2'),
348
- html('th', { class: 'highlight' }, '1.3'),
370
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.3'),
349
371
  ]),
350
372
  ]),
351
373
  html('tfoot'),
352
374
  ]).outerHTML], '']);
353
375
  assert.deepStrictEqual(
354
- inspect(parser('~~~table\n#! 1.1\n-\n# 2.1\n-\n: 3.1\n~~~')),
376
+ inspect(parser('~~~table\n#!+ 1.1\n-\n# 2.1\n-\n: 3.1\n~~~')),
355
377
  [[html('table', [
356
378
  html('thead', [
357
- html('tr', [html('th', { class: 'highlight' }, '1.1')]),
379
+ html('tr', [html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.1')]),
358
380
  html('tr', [html('th', '2.1')]),
359
381
  ]),
360
382
  html('tbody', [
@@ -363,22 +385,22 @@ describe('Unit: parser/block/extension/table', () => {
363
385
  html('tfoot'),
364
386
  ]).outerHTML], '']);
365
387
  assert.deepStrictEqual(
366
- inspect(parser('~~~table\n#:2! 1.1\n: 1.3\n~~~')),
388
+ inspect(parser('~~~table\n#:2!+ 1.1\n: 1.3\n~~~')),
367
389
  [[html('table', [
368
390
  html('thead'),
369
391
  html('tbody', [
370
392
  html('tr', [
371
- html('th', { class: 'highlight', colspan: '2' }, '1.1'),
393
+ html('th', { class: 'highlight', colspan: '2', 'data-highlight-extension': '+' }, '1.1'),
372
394
  html('td', { class: 'highlight', highlight: 'h' }, '1.3'),
373
395
  ]),
374
396
  ]),
375
397
  html('tfoot'),
376
398
  ]).outerHTML], '']);
377
399
  assert.deepStrictEqual(
378
- inspect(parser('~~~table\n#2:! 1.1\n-\n: 3.1\n~~~')),
400
+ inspect(parser('~~~table\n#2:!+ 1.1\n-\n: 3.1\n~~~')),
379
401
  [[html('table', [
380
402
  html('thead', [
381
- html('tr', [html('th', { class: 'highlight', rowspan: '2' }, '1.1')]),
403
+ html('tr', [html('th', { class: 'highlight', rowspan: '2', 'data-highlight-extension': '+' }, '1.1')]),
382
404
  ]),
383
405
  html('tbody', [
384
406
  html('tr', [html('td', { class: 'highlight', highlight: 'v' }, '3.1')]),
@@ -386,46 +408,46 @@ describe('Unit: parser/block/extension/table', () => {
386
408
  html('tfoot'),
387
409
  ]).outerHTML], '']);
388
410
  assert.deepStrictEqual(
389
- inspect(parser('~~~table\n-\n# \n#! 1.2\n-\n#! 2.1\n: 2.2\n~~~')),
411
+ inspect(parser('~~~table\n-\n# \n#!+ 1.2\n-\n#!+ 2.1\n: 2.2\n~~~')),
390
412
  [[html('table', [
391
413
  html('thead', [
392
414
  html('tr', [
393
415
  html('th'),
394
- html('th', { class: 'highlight' }, '1.2'),
416
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.2'),
395
417
  ]),
396
418
  ]),
397
419
  html('tbody', [
398
420
  html('tr', [
399
- html('th', { class: 'highlight' }, '2.1'),
421
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '2.1'),
400
422
  html('td', { class: 'highlight', highlight: 'v h' }, '2.2'),
401
423
  ]),
402
424
  ]),
403
425
  html('tfoot'),
404
426
  ]).outerHTML], '']);
405
427
  assert.deepStrictEqual(
406
- inspect(parser('~~~table\n-\n# \n#! 1.2\n-\n#! 2.1\n:! 2.2\n~~~')),
428
+ inspect(parser('~~~table\n-\n# \n#!+ 1.2\n-\n#!+ 2.1\n:! 2.2\n~~~')),
407
429
  [[html('table', [
408
430
  html('thead', [
409
431
  html('tr', [
410
432
  html('th'),
411
- html('th', { class: 'highlight' }, '1.2'),
433
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.2'),
412
434
  ]),
413
435
  ]),
414
436
  html('tbody', [
415
437
  html('tr', [
416
- html('th', { class: 'highlight' }, '2.1'),
417
- html('td', { class: 'highlight', highlight: 'v h c' }, '2.2'),
438
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '2.1'),
439
+ html('td', { class: 'highlight', 'data-highlight-level': '1', highlight: 'v h c' }, '2.2'),
418
440
  ]),
419
441
  ]),
420
442
  html('tfoot'),
421
443
  ]).outerHTML], '']);
422
444
  assert.deepStrictEqual(
423
- inspect(parser('~~~table\n-\n# 1.1\n#! 1.2\n-\n# 2.1\n:2:2 2.2\n: 2.4\n-\n#! 3.1\n: 3.4\n-\n# 4.1\n: 4.2\n~~~')),
445
+ inspect(parser('~~~table\n-\n# 1.1\n#!+ 1.2\n-\n# 2.1\n:2:2 2.2\n: 2.4\n-\n#!+ 3.1\n: 3.4\n-\n# 4.1\n: 4.2\n~~~')),
424
446
  [[html('table', [
425
447
  html('thead', [
426
448
  html('tr', [
427
449
  html('th', '1.1'),
428
- html('th', { class: 'highlight' }, '1.2'),
450
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1.2'),
429
451
  ]),
430
452
  ]),
431
453
  html('tbody', [
@@ -435,7 +457,7 @@ describe('Unit: parser/block/extension/table', () => {
435
457
  html('td', '2.4'),
436
458
  ]),
437
459
  html('tr', [
438
- html('th', { class: 'highlight' }, '3.1'),
460
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '3.1'),
439
461
  html('td', { class: 'highlight', highlight: 'h' }, '3.4'),
440
462
  ]),
441
463
  html('tr', [
@@ -446,17 +468,17 @@ describe('Unit: parser/block/extension/table', () => {
446
468
  html('tfoot'),
447
469
  ]).outerHTML], '']);
448
470
  assert.deepStrictEqual(
449
- inspect(parser('~~~table\n-\n# 1.1\n#:2! 1.2\n-\n#2:! 2.1\n: 2.2\n-\n3.2\n3.3\n~~~')),
471
+ inspect(parser('~~~table\n-\n# 1.1\n#:2!+ 1.2\n-\n#2:!+ 2.1\n: 2.2\n-\n3.2\n3.3\n~~~')),
450
472
  [[html('table', [
451
473
  html('thead', [
452
474
  html('tr', [
453
475
  html('th', '1.1'),
454
- html('th', { class: 'highlight', colspan: '2' }, '1.2'),
476
+ html('th', { class: 'highlight', colspan: '2', 'data-highlight-extension': '+' }, '1.2'),
455
477
  ]),
456
478
  ]),
457
479
  html('tbody', [
458
480
  html('tr', [
459
- html('th', { class: 'highlight', rowspan: '2' }, '2.1'),
481
+ html('th', { class: 'highlight', rowspan: '2', 'data-highlight-extension': '+' }, '2.1'),
460
482
  html('td', { class: 'highlight', highlight: 'v h' }, '2.2'),
461
483
  ]),
462
484
  html('tr', [
@@ -470,7 +492,7 @@ describe('Unit: parser/block/extension/table', () => {
470
492
  inspect(parser([
471
493
  '~~~table',
472
494
  `-\n# 1\n${[...Array(32)].map((_, i) => `: ${i + 2}`).join('\n')}`,
473
- `-\n#! 1\n${[...Array(32)].map((_, i) => `: ${i + 2}`).join('\n')}`,
495
+ `-\n#!+ 1\n${[...Array(32)].map((_, i) => `: ${i + 2}`).join('\n')}`,
474
496
  '~~~'
475
497
  ].join('\n'))),
476
498
  [[html('table', [
@@ -481,7 +503,7 @@ describe('Unit: parser/block/extension/table', () => {
481
503
  ...[...Array(32)].map((_, i) => html('td', `${i + 2}`)),
482
504
  ]),
483
505
  html('tr', [
484
- html('th', { class: 'highlight' }, '1'),
506
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1'),
485
507
  ...[...Array(32)].map((_, i) => html('td', { class: 'highlight', highlight: 'h' }, `${i + 2}`)),
486
508
  ]),
487
509
  ]),
@@ -490,7 +512,7 @@ describe('Unit: parser/block/extension/table', () => {
490
512
  inspect(parser([
491
513
  '~~~table',
492
514
  `-\n${[...Array(32)].map((_, i) => `: ${i + 1}`).join('\n')}\n# 33`,
493
- `-\n${[...Array(32)].map((_, i) => `: ${i + 1}`).join('\n')}\n#! 33`,
515
+ `-\n${[...Array(32)].map((_, i) => `: ${i + 1}`).join('\n')}\n#!+ 33`,
494
516
  '~~~'
495
517
  ].join('\n'))),
496
518
  [[html('table', [
@@ -502,14 +524,14 @@ describe('Unit: parser/block/extension/table', () => {
502
524
  ]),
503
525
  html('tr', [
504
526
  ...[...Array(32)].map((_, i) => html('td', { class: 'highlight', highlight: 'h' }, `${i + 1}`)),
505
- html('th', { class: 'highlight' }, '33'),
527
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '33'),
506
528
  ]),
507
529
  ]),
508
530
  html('tfoot')]).outerHTML], '']);
509
531
  assert.deepStrictEqual(
510
532
  inspect(parser([
511
533
  '~~~table',
512
- `-\n${[...Array(32)].map((_, i) => `# ${i + 1}`).join('\n')}\n#! 33`,
534
+ `-\n${[...Array(32)].map((_, i) => `# ${i + 1}`).join('\n')}\n#!+ 33`,
513
535
  `-\n${[...Array(33)].map((_, i) => `: ${i + 1}`).join('\n')}`,
514
536
  '~~~'
515
537
  ].join('\n'))),
@@ -517,7 +539,7 @@ describe('Unit: parser/block/extension/table', () => {
517
539
  html('thead', [
518
540
  html('tr', [
519
541
  ...[...Array(32)].map((_, i) => html('th', `${i + 1}`)),
520
- html('th', { class: 'highlight' }, '33'),
542
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '33'),
521
543
  ]),
522
544
  ]),
523
545
  html('tbody', [
@@ -537,7 +559,8 @@ describe('Unit: parser/block/extension/table', () => {
537
559
  html('thead', [
538
560
  html('tr', [
539
561
  html('th', { class: 'highlight' }, '1'),
540
- ...[...Array(6)].map((_, i) => html('th', { class: 'invalid' }, `${i + 2}`)),
562
+ ...[...Array(5)].map((_, i) => html('th', { class: 'highlight', 'data-highlight-level': `${i + 2}` }, `${i + 2}`)),
563
+ html('th', { class: 'invalid' }, '7'),
541
564
  ]),
542
565
  ]),
543
566
  html('tbody'),
@@ -561,14 +584,14 @@ describe('Unit: parser/block/extension/table', () => {
561
584
  html('tfoot'),
562
585
  ]).outerHTML], '']);
563
586
  assert.deepStrictEqual(
564
- inspect(parser('~~~table\n#! 1\n: 2\n:! 3\n~~~')),
587
+ inspect(parser('~~~table\n#!+ 1\n: 2\n:! 3\n~~~')),
565
588
  [[html('table', [
566
589
  html('thead'),
567
590
  html('tbody', [
568
591
  html('tr', [
569
- html('th', { class: 'highlight' }, '1'),
592
+ html('th', { class: 'highlight', 'data-highlight-extension': '+' }, '1'),
570
593
  html('td', { class: 'highlight', highlight: 'h' }, '2'),
571
- html('td', { class: 'highlight', highlight: 'h c' }, '3'),
594
+ html('td', { class: 'highlight', 'data-highlight-level': '1', highlight: 'h c' }, '3'),
572
595
  ]),
573
596
  ]),
574
597
  html('tfoot'),
@@ -75,10 +75,10 @@ const align: AlignParser = line(fmap(
75
75
  union([str(alignment)]),
76
76
  ([s]) => s.split('/').map(s => s.split(''))));
77
77
 
78
- const delimiter = /^[-=<>]+(?:\/[-=^v]*)?(?=[^\S\n]*\n)|^[#:](?:(?!:\D|0)\d*:(?!0)\d*)?!*(?=\s)/;
78
+ const delimiter = /^[-=<>]+(?:\/[-=^v]*)?(?=[^\S\n]*\n)|^[#:](?:(?!:\D|0)\d*:(?!0)\d*)?(?:!+[+]?)?(?=\s)/;
79
79
 
80
80
  const head: CellParser.HeadParser = creation(1, false, block(fmap(open(
81
- str(/^#(?:(?!:\D|0)\d*:(?!0)\d*)?!*(?=\s)/),
81
+ str(/^#(?:(?!:\D|0)\d*:(?!0)\d*)?(?:!+[+]?)?(?=\s)/),
82
82
  rewrite(
83
83
  inits([
84
84
  anyline,
@@ -90,7 +90,7 @@ const head: CellParser.HeadParser = creation(1, false, block(fmap(open(
90
90
  false));
91
91
 
92
92
  const data: CellParser.DataParser = creation(1, false, block(fmap(open(
93
- str(/^:(?:(?!:\D|0)\d*:(?!0)\d*)?!*(?=\s)/),
93
+ str(/^:(?:(?!:\D|0)\d*:(?!0)\d*)?(?:!+[+]?)?(?=\s)/),
94
94
  rewrite(
95
95
  inits([
96
96
  anyline,
@@ -110,28 +110,40 @@ const dataline: CellParser.DatalineParser = creation(1, false, line(
110
110
  ]))));
111
111
 
112
112
  function attributes(source: string) {
113
- let [, rowspan = undefined, colspan = undefined, highlight = undefined] = source.match(/^.(?:(\d+)?:(\d+)?)?(!+)?$/) ?? [];
113
+ let [, rowspan = undefined, colspan = undefined, highlight = undefined, extension = undefined] =
114
+ source.match(/^[#:](?:(\d+)?:(\d+)?)?(?:(!+)([+]?))?$/) ?? [];
114
115
  assert(rowspan?.[0] !== '0');
115
116
  assert(colspan?.[0] !== '0');
116
117
  rowspan === '1' ? rowspan = undefined : undefined;
117
118
  colspan === '1' ? colspan = undefined : undefined;
118
119
  rowspan &&= `${max(0, min(+rowspan, 65534))}`;
119
120
  colspan &&= `${max(0, min(+colspan, 1000))}`;
120
- highlight &&= highlight.length > 0 ? `${highlight.length}` : undefined;
121
- const valid = !highlight
122
- || source[0] === '#' && +highlight <= 1
123
- || source[0] === ':' && +highlight <= 6;
121
+ extension ||= undefined;
122
+ const level = highlight?.length ?? 0;
123
+ const validH = !highlight
124
+ || source[0] === '#' && level <= 6
125
+ || source[0] === ':' && level <= 6;
126
+ const validE = source[0] === '#' || extension !== '+';
127
+ const valid = validH && validE;
124
128
  return {
125
129
  class: valid ? highlight && 'highlight' : 'invalid',
126
130
  rowspan,
127
131
  colspan,
128
- ...valid
129
- ? { 'data-highlight-level': +highlight! > 1 ? highlight : undefined }
130
- : {
131
- 'data-invalid-syntax': 'table',
132
- 'data-invalid-type': 'syntax',
133
- 'data-invalid-message': 'Too much highlight level',
134
- },
132
+ ...
133
+ !validH && {
134
+ 'data-invalid-syntax': 'table',
135
+ 'data-invalid-type': 'syntax',
136
+ 'data-invalid-message': 'Too much highlight level',
137
+ } ||
138
+ !validE && {
139
+ 'data-invalid-syntax': 'table',
140
+ 'data-invalid-type': 'syntax',
141
+ 'data-invalid-message': 'Extensible cells are only head cells',
142
+ } ||
143
+ {
144
+ 'data-highlight-level': level > 1 ? `${level}` : undefined,
145
+ 'data-highlight-extension': extension,
146
+ },
135
147
  };
136
148
  }
137
149
 
@@ -143,7 +155,8 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
143
155
  const valigns: ('middle' | 'top' | 'bottom' | '')[] = [];
144
156
  let target = thead;
145
157
  let ranges: Record<number, Record<number, HTMLTableCellElement>> = {};
146
- let verticalHighlights = 0n;
158
+ let verticalHighlightExtensions = 0n;
159
+ let verticalHighlightLevels: string[] = [];
147
160
  ROW:
148
161
  for (let i = 0; i < rows.length; ++i) {
149
162
  // Copy to make them retryable.
@@ -215,9 +228,11 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
215
228
  const row = html('tr');
216
229
  let heads = 0n;
217
230
  let highlights = 0n;
231
+ let highlightExtensions = 0n;
232
+ let highlightLevels: string[] = [];
218
233
  let hasDataCell = false;
219
- let lHeadCellIdx: bigint;
220
- let rHeadCellIdx: bigint;
234
+ let lHeadCellIndex: bigint;
235
+ let rHeadCellIndex: bigint;
221
236
  for (let j = 0; j < cells.length; ++j) {
222
237
  const jn = BigInt(j);
223
238
  const isVirtual = !!ranges[i]?.[j];
@@ -225,14 +240,16 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
225
240
  ? splice(cells, j, 0, undefined) && ranges[i][j]
226
241
  : cells[j];
227
242
  const isHeadCell = cell.tagName === 'TH';
228
- heads |= BigInt(isHeadCell) << jn;
229
- highlights |= BigInt(cell.className === 'highlight') << jn;
243
+ heads |= isHeadCell ? 1n << jn : 0n;
244
+ highlights |= cell.className === 'highlight' ? 1n << jn : 0n;
245
+ highlightExtensions |= cell.getAttribute('data-highlight-extension') ? 1n << jn : 0n;
246
+ highlightLevels[j] = cell.getAttribute('data-highlight-level') ?? '1';
230
247
  hasDataCell ||= !isHeadCell;
231
248
  if (isHeadCell && !hasDataCell) {
232
- lHeadCellIdx = jn;
249
+ lHeadCellIndex = jn;
233
250
  }
234
251
  if (isHeadCell && hasDataCell) {
235
- rHeadCellIdx ??= jn;
252
+ rHeadCellIndex ??= jn;
236
253
  }
237
254
  const rowSpan = cell.rowSpan;
238
255
  assert(rowSpan > 0);
@@ -249,6 +266,8 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
249
266
  splice(cells, j + 1, 0, ...Array(colSpan - 1));
250
267
  heads |= heads & 1n << jn && ~(~0n << BigInt(colSpan)) << jn;
251
268
  highlights |= highlights & 1n << jn && ~(~0n << BigInt(colSpan)) << jn;
269
+ highlightExtensions |= highlightExtensions & 1n << jn && ~(~0n << BigInt(colSpan)) << jn;
270
+ splice(highlightLevels, j + 1, 0, ...Array(colSpan - 1));
252
271
  j += colSpan - 1;
253
272
  }
254
273
  if (target === thead) {
@@ -285,22 +304,39 @@ function format(rows: Tree<RowParser>[]): HTMLTableSectionElement[] {
285
304
  target.appendChild(row);
286
305
  switch (target) {
287
306
  case thead:
288
- verticalHighlights = heads & highlights;
307
+ verticalHighlightExtensions = highlightExtensions;
308
+ verticalHighlightLevels = highlightLevels;
289
309
  continue;
290
310
  case tbody:
291
- lHeadCellIdx ??= -1n;
292
- rHeadCellIdx ??= -1n;
293
- const tHighlights = verticalHighlights;
294
- const horizontalHighlights = heads & highlights;
295
- const lHighlight = ~lHeadCellIdx && horizontalHighlights & 1n << lHeadCellIdx;
296
- const rHighlight = ~rHeadCellIdx && horizontalHighlights & 1n << rHeadCellIdx;
311
+ lHeadCellIndex ??= -1n;
312
+ rHeadCellIndex ??= -1n;
313
+ const tHighlights = verticalHighlightExtensions;
314
+ const horizontalHighlights = highlightExtensions;
315
+ const horizontalHighlightLevels = highlightLevels;
316
+ const lHighlight = ~lHeadCellIndex && horizontalHighlights & 1n << lHeadCellIndex;
317
+ const rHighlight = ~rHeadCellIndex && horizontalHighlights & 1n << rHeadCellIndex;
297
318
  for (let i = 0, m = 1n; i < cells.length; ++i, m <<= 1n) {
298
319
  const cell = cells[i];
299
320
  if (!cell) continue;
300
321
  if (heads & m) continue;
301
322
  assert(cell.tagName === 'TD');
302
- if (!(lHighlight || rHighlight || tHighlights & m || highlights & m)) continue;
303
- cell.classList.add('highlight');
323
+ switch (m) {
324
+ case highlights & m:
325
+ assert(cell.className === 'highlight');
326
+ assert(horizontalHighlightLevels[i]);
327
+ (lHighlight || rHighlight) && cell.setAttribute('data-highlight-level', horizontalHighlightLevels[i]);
328
+ break;
329
+ case lHighlight && m:
330
+ case rHighlight && m:
331
+ cell.classList.add('highlight');
332
+ break;
333
+ case tHighlights & m:
334
+ cell.classList.add('highlight');
335
+ +verticalHighlightLevels[i] > 1 && cell.setAttribute('data-highlight-level', verticalHighlightLevels[i]);
336
+ break;
337
+ default:
338
+ continue;
339
+ }
304
340
  assert(!+cell.setAttribute('highlight', [
305
341
  '',
306
342
  'c',
@@ -13,7 +13,7 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
13
13
  url => `{ ${url} }`,
14
14
  union([unsafelink])))));
15
15
 
16
- export const lineurl: AutolinkParser.UrlParser.LineUrlParser = open(
16
+ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
17
17
  linebreak,
18
18
  tails([
19
19
  str('!'),
@@ -22,7 +22,7 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = open(
22
22
  convert(
23
23
  url => `{ ${url} }`,
24
24
  unsafelink)),
25
- ]));
25
+ ])));
26
26
 
27
27
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(precedence(2, union([
28
28
  surround('(', some(union([bracket, unescsource]), ')'), ')', true),
@@ -1,5 +1,5 @@
1
1
  import { AutolinkParser } from '../inline';
2
- import { union, some, syntax, constraint, validate, focus, fmap } from '../../combinator';
2
+ import { union, some, syntax, constraint, validate, focus, lazy, fmap } from '../../combinator';
3
3
  import { url, lineurl } from './autolink/url';
4
4
  import { email } from './autolink/email';
5
5
  import { channel } from './autolink/channel';
@@ -11,7 +11,7 @@ import { str } from '../source';
11
11
  import { Syntax, State } from '../context';
12
12
  import { stringify } from '../util';
13
13
 
14
- export const autolink: AutolinkParser =
14
+ export const autolink: AutolinkParser = lazy(() =>
15
15
  validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i,
16
16
  constraint(State.autolink, false,
17
17
  syntax(Syntax.autolink, 1, 1, ~State.shortcut,
@@ -44,4 +44,4 @@ export const autolink: AutolinkParser =
44
44
  anchor,
45
45
  ])),
46
46
  ns => ns.length === 1 ? ns : [stringify(ns)]),
47
- ]))));
47
+ ])))));