securemark 0.264.0 → 0.265.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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.265.0
4
+
5
+ - Change ulist and olist parsers to index list items.
6
+ - Change link parser to accept autolinks.
7
+
3
8
  ## 0.264.0
4
9
 
5
10
  - Change signature syntax.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.264.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.265.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
2
2
  (function webpackUniversalModuleDefinition(root, factory) {
3
3
  if(typeof exports === 'object' && typeof module === 'object')
4
4
  module.exports = factory(require("Prism"), require("DOMPurify"));
@@ -4151,7 +4151,7 @@ function format(source) {
4151
4151
  return source.replace(/\r\n?/g, '\n');
4152
4152
  }
4153
4153
  function sanitize(source) {
4154
- return source.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(^|[^\u1820\u1821])\u180E/g, `$1${UNICODE_REPLACEMENT_CHARACTER}`).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/g, char => char.length === 1 ? UNICODE_REPLACEMENT_CHARACTER : char);
4154
+ return source.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(?<![\u1820\u1821])\u180E/g, UNICODE_REPLACEMENT_CHARACTER).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/g, char => char.length === 1 ? UNICODE_REPLACEMENT_CHARACTER : char);
4155
4155
  }
4156
4156
  // https://dev.w3.org/html5/html-author/charref
4157
4157
  // https://en.wikipedia.org/wiki/Whitespace_character
@@ -4263,7 +4263,7 @@ exports.parse = parse;
4263
4263
 
4264
4264
  /***/ }),
4265
4265
 
4266
- /***/ 6578:
4266
+ /***/ 7185:
4267
4267
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4268
4268
 
4269
4269
  "use strict";
@@ -4366,7 +4366,7 @@ Object.defineProperty(exports, "__esModule", ({
4366
4366
  }));
4367
4367
  exports.blockquote = exports.segment = void 0;
4368
4368
  const combinator_1 = __webpack_require__(2087);
4369
- const autolink_1 = __webpack_require__(6578);
4369
+ const autolink_1 = __webpack_require__(7185);
4370
4370
  const source_1 = __webpack_require__(6743);
4371
4371
  const parse_1 = __webpack_require__(5013);
4372
4372
  const dom_1 = __webpack_require__(3252);
@@ -4374,7 +4374,7 @@ exports.segment = (0, combinator_1.block)((0, combinator_1.validate)(['!>', '>']
4374
4374
  exports.blockquote = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.rewrite)(exports.segment, (0, combinator_1.union)([(0, combinator_1.open)(/^(?=>)/, source), (0, combinator_1.open)(/^!(?=>)/, markdown)]))));
4375
4375
  const opener = /^(?=>>+(?:$|\s))/;
4376
4376
  const indent = (0, combinator_1.block)((0, combinator_1.open)(opener, (0, combinator_1.some)(source_1.contentline, /^>(?:$|\s)/)), false);
4377
- const unindent = source => source.replace(/(^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '$1');
4377
+ const unindent = source => source.replace(/(?<=^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '');
4378
4378
  const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)((0, combinator_1.some)(autolink_1.autolink), ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
4379
4379
  const markdown = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, markdown)), (0, combinator_1.creation)(99, false, (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, ({
4380
4380
  source,
@@ -4406,7 +4406,7 @@ Object.defineProperty(exports, "__esModule", ({
4406
4406
  exports.codeblock = exports.segment_ = exports.segment = void 0;
4407
4407
  const parser_1 = __webpack_require__(6728);
4408
4408
  const combinator_1 = __webpack_require__(2087);
4409
- const autolink_1 = __webpack_require__(6578);
4409
+ const autolink_1 = __webpack_require__(7185);
4410
4410
  const dom_1 = __webpack_require__(3252);
4411
4411
  const opener = /^(`{3,})(?!`)([^\n]*)(?:$|\n)/;
4412
4412
  const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/i;
@@ -4539,8 +4539,6 @@ exports.aside = (0, combinator_1.block)((0, combinator_1.validate)('~~~', (0, co
4539
4539
  references
4540
4540
  }
4541
4541
  }, context);
4542
- // Bug: Firefox
4543
- //const heading = document.querySelector(':scope > h1:first-child');
4544
4542
  const heading = 'H1 H2 H3 H4 H5 H6'.split(' ').includes(document.firstElementChild?.tagName) && document.firstElementChild;
4545
4543
  if (!heading) return [(0, dom_1.html)('pre', {
4546
4544
  class: 'invalid',
@@ -5455,7 +5453,7 @@ const parser_1 = __webpack_require__(6728);
5455
5453
  const combinator_1 = __webpack_require__(2087);
5456
5454
  const math_1 = __webpack_require__(8946);
5457
5455
  const source_1 = __webpack_require__(6743);
5458
- const autolink_1 = __webpack_require__(6578);
5456
+ const autolink_1 = __webpack_require__(7185);
5459
5457
  const dom_1 = __webpack_require__(3252);
5460
5458
  exports.syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
5461
5459
  exports.quote = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, false, (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)('>', (0, combinator_1.union)([(0, combinator_1.rewrite)((0, combinator_1.some)((0, combinator_1.validate)(new RegExp(exports.syntax.source.split('|')[0]), source_1.anyline)), qblock), (0, combinator_1.rewrite)((0, combinator_1.validate)(new RegExp(exports.syntax.source.split('|').slice(1).join('|')), source_1.anyline), (0, combinator_1.line)((0, combinator_1.union)([(0, source_1.str)(/^.+/)])))])), ns => [(0, dom_1.html)('span', ns.length > 1 ? {
@@ -5516,7 +5514,7 @@ Object.defineProperty(exports, "__esModule", ({
5516
5514
  }));
5517
5515
  exports.sidefence = void 0;
5518
5516
  const combinator_1 = __webpack_require__(2087);
5519
- const autolink_1 = __webpack_require__(6578);
5517
+ const autolink_1 = __webpack_require__(7185);
5520
5518
  const source_1 = __webpack_require__(6743);
5521
5519
  const dom_1 = __webpack_require__(3252);
5522
5520
  exports.sidefence = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.focus)(/^(?=\|+(?:[^\S\n]|\n\|))(?:\|+(?:[^\S\n][^\n]*)?(?:$|\n))+$/, (0, combinator_1.union)([source])), ([el]) => [(0, dom_1.define)(el, {
@@ -5526,7 +5524,7 @@ exports.sidefence = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, com
5526
5524
  'data-invalid-message': 'Reserved syntax'
5527
5525
  })])));
5528
5526
  const opener = /^(?=\|\|+(?:$|\s))/;
5529
- const unindent = source => source.replace(/(^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '$1');
5527
+ const unindent = source => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
5530
5528
  const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.focus)(/^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)((0, combinator_1.some)(autolink_1.autolink), ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
5531
5529
 
5532
5530
  /***/ }),
@@ -5687,7 +5685,7 @@ const insertion_1 = __webpack_require__(2945);
5687
5685
  const deletion_1 = __webpack_require__(7501);
5688
5686
  const mark_1 = __webpack_require__(2480);
5689
5687
  const emphasis_1 = __webpack_require__(3867);
5690
- const strong_1 = __webpack_require__(8072);
5688
+ const strong_1 = __webpack_require__(6578);
5691
5689
  const code_1 = __webpack_require__(5771);
5692
5690
  const media_1 = __webpack_require__(1303);
5693
5691
  const htmlentity_1 = __webpack_require__(1562);
@@ -6145,29 +6143,27 @@ function identity(text, name = 'index') {
6145
6143
  exports.identity = identity;
6146
6144
  function text(source, optional = false) {
6147
6145
  const indexer = source.querySelector(':scope > .indexer');
6148
- if (!indexer && optional) return '';
6149
6146
  const index = indexer?.getAttribute('data-index');
6150
6147
  if (index) return index;
6148
+ if (index === '' && optional) return '';
6151
6149
  const target = source.cloneNode(true);
6152
6150
  for (let es = target.querySelectorAll('code[data-src], .math[data-src], .comment, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'), len = es.length, i = 0; i < len; ++i) {
6153
6151
  const el = es[i];
6154
6152
  switch (el.tagName) {
6155
6153
  case 'CODE':
6156
- (0, dom_1.define)(el, el.getAttribute('data-src'));
6154
+ el.replaceWith(el.getAttribute('data-src'));
6157
6155
  continue;
6158
6156
  case 'RT':
6159
6157
  case 'RP':
6158
+ case 'BR':
6160
6159
  case 'UL':
6161
6160
  case 'OL':
6162
6161
  el.remove();
6163
6162
  continue;
6164
- case 'BR':
6165
- el.replaceWith('\n');
6166
- continue;
6167
6163
  }
6168
6164
  switch (el.className) {
6169
6165
  case 'math':
6170
- (0, dom_1.define)(el, el.getAttribute('data-src'));
6166
+ el.replaceWith(el.getAttribute('data-src'));
6171
6167
  continue;
6172
6168
  case 'comment':
6173
6169
  case 'checkbox':
@@ -6411,11 +6407,9 @@ Object.defineProperty(exports, "__esModule", ({
6411
6407
  value: true
6412
6408
  }));
6413
6409
  exports.resolve = exports.option = exports.uri = exports.unsafelink = exports.link = void 0;
6414
- const parser_1 = __webpack_require__(6728);
6415
6410
  const combinator_1 = __webpack_require__(2087);
6416
6411
  const inline_1 = __webpack_require__(1160);
6417
6412
  const html_1 = __webpack_require__(5994);
6418
- const autolink_1 = __webpack_require__(6578);
6419
6413
  const source_1 = __webpack_require__(6743);
6420
6414
  const visibility_1 = __webpack_require__(7618);
6421
6415
  const util_1 = __webpack_require__(9437);
@@ -6433,22 +6427,11 @@ const medialink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(16 /
6433
6427
  exports.unsafelink = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(10, (0, combinator_1.precedence)(2, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.some)((0, combinator_1.union)([source_1.unescsource]), ']'), ']')), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))])), ([params, content = []], rest, context) => parse(content, params, rest, context)))));
6434
6428
  exports.uri = (0, combinator_1.union)([(0, combinator_1.open)(/^[^\S\n]+/, (0, source_1.str)(/^\S+/)), (0, source_1.str)(/^[^\s{}]+/)]);
6435
6429
  exports.option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+nofollow(?=[^\S\n]|})/), () => [` rel="nofollow"`]), (0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|})/), (0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[^\s{}]+/), opt => [` \\${opt.slice(1)}`])]);
6436
- const autolink = (0, combinator_1.state)(2 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.shortcut */, autolink_1.autolink));
6437
6430
  function parse(content, params, rest, context) {
6438
6431
  if (content.length !== 0 && (0, visibility_1.trimNode)(content).length === 0) return;
6439
- content = (0, dom_1.defrag)(content);
6440
- for (let source = (0, util_1.stringify)(content); source;) {
6441
- if (/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i.test(source)) return;
6442
- const result = autolink({
6443
- source,
6444
- context
6445
- });
6446
- if (typeof (0, parser_1.eval)(result, [])[0] === 'object') return;
6447
- source = (0, parser_1.exec)(result, '');
6448
- }
6449
6432
  const INSECURE_URI = params.shift();
6450
6433
  const uri = new url_1.ReadonlyURL(resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location), context.host?.href || location.href);
6451
- const el = elem(INSECURE_URI, content, uri, context.host?.origin || location.origin);
6434
+ const el = elem(INSECURE_URI, (0, dom_1.defrag)(content), uri, context.host?.origin || location.origin);
6452
6435
  if (el.className === 'invalid') return [[el], rest];
6453
6436
  return [[(0, dom_1.define)(el, (0, html_1.attributes)('link', [], optspec, params))], rest];
6454
6437
  }
@@ -6459,6 +6442,10 @@ function elem(INSECURE_URI, content, uri, origin) {
6459
6442
  case 'http:':
6460
6443
  case 'https:':
6461
6444
  switch (true) {
6445
+ case /[a-z][0-9]*:\/{0,2}\S/i.test((0, util_1.stringify)(content)):
6446
+ type = 'content';
6447
+ message = 'URI must not be contained';
6448
+ break;
6462
6449
  case INSECURE_URI.slice(0, 2) === '^/' && /\/\.\.?(?:\/|$)/.test(INSECURE_URI.slice(0, INSECURE_URI.search(/[?#]|$/))):
6463
6450
  type = 'argument';
6464
6451
  message = 'Dot-segments cannot be used in subresource paths';
@@ -6484,6 +6471,7 @@ function elem(INSECURE_URI, content, uri, origin) {
6484
6471
  type = 'content';
6485
6472
  message = 'Invalid content';
6486
6473
  }
6474
+ break;
6487
6475
  }
6488
6476
  return (0, dom_1.html)('a', {
6489
6477
  class: 'invalid',
@@ -6512,7 +6500,7 @@ function decode(uri) {
6512
6500
  const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
6513
6501
  try {
6514
6502
  let path = decodeURI(uri.slice(origin.length));
6515
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i.test(path)) {
6503
+ if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
6516
6504
  path = uri.slice(origin.length);
6517
6505
  }
6518
6506
  uri = origin + path;
@@ -6831,7 +6819,7 @@ exports.shortmedia = (0, combinator_1.rewrite)((0, combinator_1.constraint)(8 /*
6831
6819
 
6832
6820
  /***/ }),
6833
6821
 
6834
- /***/ 8072:
6822
+ /***/ 6578:
6835
6823
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6836
6824
 
6837
6825
  "use strict";
@@ -6894,8 +6882,6 @@ function* figure(target, footnotes, opts = {}) {
6894
6882
  let base = '0';
6895
6883
  let bases = base.split('.');
6896
6884
  let index = bases;
6897
- // Bug: Firefox
6898
- //for (let defs = target.querySelectorAll(':scope > figure[data-label], :scope > h1, :scope > h2'), len = defs.length, i = 0; i < len; ++i) {
6899
6885
  for (let defs = target.querySelectorAll('figure[data-label], h1, h2'), len = defs.length, i = 0; i < len; ++i) {
6900
6886
  yield;
6901
6887
  const def = defs[i];
@@ -7056,8 +7042,6 @@ const indexee_1 = __webpack_require__(1269);
7056
7042
  const queue_1 = __webpack_require__(4934);
7057
7043
  const dom_1 = __webpack_require__(3252);
7058
7044
  function* footnote(target, footnotes, opts = {}, bottom = null) {
7059
- // Bug: Firefox
7060
- //target.querySelectorAll(`:scope > .annotations`).forEach(el => el.remove());
7061
7045
  for (let es = target.querySelectorAll(`.annotations`), len = es.length, i = 0; i < len; ++i) {
7062
7046
  const el = es[i];
7063
7047
  el.parentNode === target && el.remove();
@@ -7076,8 +7060,6 @@ function build(syntax, marker, splitter) {
7076
7060
  const defs = new Map();
7077
7061
  const buffer = new queue_1.MultiQueue();
7078
7062
  const titles = new Map();
7079
- // Bug: Firefox
7080
- //const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
7081
7063
  const splitters = [];
7082
7064
  for (let es = target.querySelectorAll(splitter ?? '_'), len = es.length, i = 0; i < len; ++i) {
7083
7065
  const el = es[i];
@@ -8331,8 +8313,6 @@ Object.defineProperty(exports, "__esModule", ({
8331
8313
  exports.toc = void 0;
8332
8314
  const array_1 = __webpack_require__(8112);
8333
8315
  const dom_1 = __webpack_require__(3252);
8334
- // Bug: Firefox
8335
- //const selector = `:scope > :is(h1, h2, h3, h4, h5, h6, aside.aside)[id]`;
8336
8316
  const selector = ':is(h1, h2, h3, h4, h5, h6, aside.aside)[id]';
8337
8317
  function toc(source) {
8338
8318
  const hs = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.264.0",
3
+ "version": "0.265.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",
@@ -4,7 +4,8 @@ import { unshift, push } from 'spica/array';
4
4
 
5
5
  type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
6
6
 
7
- export function some<P extends Parser<unknown>>(parser: P, end?: string | RegExp | number, delimiters?: readonly DelimiterOption[], limit?: number): P;
7
+ export function some<P extends Parser<unknown>>(parser: P, limit?: number): P;
8
+ export function some<P extends Parser<unknown>>(parser: P, end?: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
8
9
  export function some<T>(parser: Parser<T>, end?: string | RegExp | number, delimiters: readonly DelimiterOption[] = [], limit = -1): Parser<T> {
9
10
  if (typeof end === 'number') return some(parser, undefined, delimiters, end);
10
11
  assert(parser);
@@ -15,7 +15,7 @@ function format(source: string): string {
15
15
 
16
16
  function sanitize(source: string): string {
17
17
  return source
18
- .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(^|[^\u1820\u1821])\u180E/g, `$1${UNICODE_REPLACEMENT_CHARACTER}`)
18
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]|[\u2006\u200B-\u200F\u202A-\u202F\u2060\uFEFF]|(?<![\u1820\u1821])\u180E/g, UNICODE_REPLACEMENT_CHARACTER)
19
19
  .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/g, char =>
20
20
  char.length === 1
21
21
  ? UNICODE_REPLACEMENT_CHARACTER
@@ -16,7 +16,7 @@ export const blockquote: BlockquoteParser = lazy(() => block(rewrite(segment, un
16
16
 
17
17
  const opener = /^(?=>>+(?:$|\s))/;
18
18
  const indent = block(open(opener, some(contentline, /^>(?:$|\s)/)), false);
19
- const unindent = (source: string) => source.replace(/(^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '$1');
19
+ const unindent = (source: string) => source.replace(/(?<=^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '');
20
20
 
21
21
  const source: BlockquoteParser.SourceParser = lazy(() => fmap(
22
22
  some(creation(1, false, union([
@@ -26,8 +26,6 @@ export const aside: ExtensionParser.AsideParser = block(validate('~~~', fmap(
26
26
  },
27
27
  }, context);
28
28
  assert(!document.querySelector('[id]'));
29
- // Bug: Firefox
30
- //const heading = document.querySelector(':scope > h1:first-child');
31
29
  const heading = 'H1 H2 H3 H4 H5 H6'.split(' ').includes(document.firstElementChild?.tagName!) && document.firstElementChild as HTMLHeadingElement;
32
30
  if (!heading) return [html('pre', {
33
31
  class: 'invalid',
@@ -44,8 +44,8 @@ describe('Unit: parser/block/extension/figure', () => {
44
44
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\n\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\n\\\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext">\\</span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\n!https://caption\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext">!<a class="url" href="https://caption" target="_blank">https://caption</a></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
47
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n- a\n~~~')), [['<figure data-type="list" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><ul><li>a</li></ul></div></figure>'], '']);
48
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n1. a\n~~~')), [['<figure data-type="list" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><ol><li>a</li></ol></div></figure>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n- a\n~~~')), [['<figure data-type="list" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><ul><li id="index:a">a</li></ul></div></figure>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n1. a\n~~~')), [['<figure data-type="list" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><ol><li id="index:a">a</li></ol></div></figure>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n|\n|-\n|\n~~~')), [['<figure data-type="table" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><table><thead><tr></tr></thead><tbody><tr></tr></tbody></table></div></figure>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n```\n\n```\n~~~')), [['<figure data-type="text" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><pre class="text"></pre></div></figure>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n```\n~~~\n```\n\n~~~')), [['<figure data-type="text" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><pre class="text">~~~</pre></div></figure>'], '']);
@@ -39,12 +39,12 @@ describe('Unit: parser/block/olist', () => {
39
39
  // filled
40
40
  assert.deepStrictEqual(inspect(parser('1. \\')), [['<ol><li></li></ol>'], '']);
41
41
  assert.deepStrictEqual(inspect(parser('1. \\\n')), [['<ol><li></li></ol>'], '']);
42
- assert.deepStrictEqual(inspect(parser('1. -')), [['<ol><li>-</li></ol>'], '']);
43
- assert.deepStrictEqual(inspect(parser('1. -\n')), [['<ol><li>-</li></ol>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('1. -')), [['<ol><li id="index:-">-</li></ol>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('1. -\n')), [['<ol><li id="index:-">-</li></ol>'], '']);
44
44
  // pending
45
45
  assert.deepStrictEqual(inspect(parser('(1) ')), [['<ol data-format="paren"><li></li></ol>'], '']);
46
46
  // filled
47
- assert.deepStrictEqual(inspect(parser('(1) a')), [['<ol data-format="paren"><li>a</li></ol>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('(1) a')), [['<ol data-format="paren"><li id="index:a">a</li></ol>'], '']);
48
48
  });
49
49
 
50
50
  it('multiple', () => {
@@ -55,8 +55,8 @@ describe('Unit: parser/block/olist', () => {
55
55
  assert.deepStrictEqual(inspect(parser('0.\n0. ')), [['<ol><li></li><li></li></ol>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('0.\n0.\n')), [['<ol><li></li><li></li></ol>'], '']);
57
57
  // filled
58
- assert.deepStrictEqual(inspect(parser('0. 1\n0. 2')), [['<ol><li>1</li><li>2</li></ol>'], '']);
59
- assert.deepStrictEqual(inspect(parser('0. 1\n0. 2\n0. 3')), [['<ol><li>1</li><li>2</li><li>3</li></ol>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('0. 1\n0. 2')), [['<ol><li id="index:1">1</li><li id="index:2">2</li></ol>'], '']);
59
+ assert.deepStrictEqual(inspect(parser('0. 1\n0. 2\n0. 3')), [['<ol><li id="index:1">1</li><li id="index:2">2</li><li id="index:3">3</li></ol>'], '']);
60
60
  // pending
61
61
  assert.deepStrictEqual(inspect(parser('(1) \n(')), [['<ol data-format="paren"><li></li><li></li></ol>'], '']);
62
62
  assert.deepStrictEqual(inspect(parser('(1) \n(\n')), [['<ol data-format="paren"><li></li><li></li></ol>'], '']);
@@ -67,21 +67,21 @@ describe('Unit: parser/block/olist', () => {
67
67
  // filled
68
68
  assert.deepStrictEqual(inspect(parser('(1) \n(1) ')), [['<ol data-format="paren"><li></li><li></li></ol>'], '']);
69
69
  // invalid
70
- assert.deepStrictEqual(inspect(parser('0. \n0 ')), [['<ol><li></li><li><span class="invalid">0 </span></li></ol>'], '']);
70
+ assert.deepStrictEqual(inspect(parser('0. \n0 ')), [['<ol><li></li><li id="index:0"><span class="invalid">0 </span></li></ol>'], '']);
71
71
  });
72
72
 
73
73
  it('nest', () => {
74
74
  assert.deepStrictEqual(inspect(parser('0.\n 0')), [['<ol><li><br><ol><li></li></ol></li></ol>'], '']);
75
- assert.deepStrictEqual(inspect(parser('0. 1\n 0')), [['<ol><li>1<ol><li></li></ol></li></ol>'], '']);
76
- assert.deepStrictEqual(inspect(parser('0. 1\n 0.')), [['<ol><li>1<ol><li></li></ol></li></ol>'], '']);
77
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. ')), [['<ol><li>1<ol><li></li></ol></li></ol>'], '']);
78
- assert.deepStrictEqual(inspect(parser('0. 1\n 0.\n')), [['<ol><li>1<ol><li></li></ol></li></ol>'], '']);
79
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2')), [['<ol><li>1<ol><li>2</li></ol></li></ol>'], '']);
80
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n0. 3')), [['<ol><li>1<ol><li>2</li></ol></li><li>3</li></ol>'], '']);
81
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li>1<ol><li>2</li><li>3</li></ol></li></ol>'], '']);
82
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li>1<ol><li>2<ol><li>3</li></ol></li></ol></li></ol>'], '']);
83
- assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li>1<ol><li>2</li></ol></li><li><span class="invalid"> 0. 3</span></li></ol>'], '']);
84
- assert.deepStrictEqual(inspect(parser('0. !http://host')), [['<ol><li>!<a class="url" href="http://host" target="_blank">http://host</a></li></ol>'], '']);
75
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0')), [['<ol><li id="index:1">1<ol><li></li></ol></li></ol>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0.')), [['<ol><li id="index:1">1<ol><li></li></ol></li></ol>'], '']);
77
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. ')), [['<ol><li id="index:1">1<ol><li></li></ol></li></ol>'], '']);
78
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0.\n')), [['<ol><li id="index:1">1<ol><li></li></ol></li></ol>'], '']);
79
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2')), [['<ol><li id="index:1">1<ol><li id="index:2">2</li></ol></li></ol>'], '']);
80
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n0. 3')), [['<ol><li id="index:1">1<ol><li id="index:2">2</li></ol></li><li id="index:3">3</li></ol>'], '']);
81
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li id="index:1">1<ol><li id="index:2">2</li><li id="index:3">3</li></ol></li></ol>'], '']);
82
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li id="index:1">1<ol><li id="index:2">2<ol><li id="index:3">3</li></ol></li></ol></li></ol>'], '']);
83
+ assert.deepStrictEqual(inspect(parser('0. 1\n 0. 2\n 0. 3')), [['<ol><li id="index:1">1<ol><li id="index:2">2</li></ol></li><li id="index:0._3"><span class="invalid"> 0. 3</span></li></ol>'], '']);
84
+ assert.deepStrictEqual(inspect(parser('0. !http://host')), [['<ol><li id="index:!http://host">!<a class="url" href="http://host" target="_blank">http://host</a></li></ol>'], '']);
85
85
  });
86
86
 
87
87
  it('index', () => {
@@ -103,10 +103,11 @@ describe('Unit: parser/block/olist', () => {
103
103
  assert.deepStrictEqual(inspect(parser('(1)-1-1 ')), [['<ol data-format="paren"><li data-marker="(1)-1-1"></li></ol>'], '']);
104
104
  assert.deepStrictEqual(inspect(parser('(1) \n(1)-')), [['<ol data-format="paren"><li></li><li data-marker="(1)-"></li></ol>'], '']);
105
105
  assert.deepStrictEqual(inspect(parser('(1) \n(1)-1')), [['<ol data-format="paren"><li></li><li data-marker="(1)-1"></li></ol>'], '']);
106
- assert.deepStrictEqual(inspect(parser('1. \n1--')), [['<ol><li></li><li><span class="invalid">1--</span></li></ol>'], '']);
107
- assert.deepStrictEqual(inspect(parser('1. \n1--. ')), [['<ol><li></li><li><span class="invalid">1--. </span></li></ol>'], '']);
108
- assert.deepStrictEqual(inspect(parser('(1) \n(1)--')), [['<ol data-format="paren"><li></li><li><span class="invalid">(1)--</span></li></ol>'], '']);
109
- assert.deepStrictEqual(inspect(parser('(1) \n(1)-- ')), [['<ol data-format="paren"><li></li><li><span class="invalid">(1)-- </span></li></ol>'], '']);
106
+ assert.deepStrictEqual(inspect(parser('1. \n1--')), [['<ol><li></li><li id="index:1--"><span class="invalid">1--</span></li></ol>'], '']);
107
+ assert.deepStrictEqual(inspect(parser('1. \n1--. ')), [['<ol><li></li><li id="index:1--."><span class="invalid">1--. </span></li></ol>'], '']);
108
+ assert.deepStrictEqual(inspect(parser('(1) \n(1)--')), [['<ol data-format="paren"><li></li><li id="index:(1)--"><span class="invalid">(1)--</span></li></ol>'], '']);
109
+ assert.deepStrictEqual(inspect(parser('(1) \n(1)-- ')), [['<ol data-format="paren"><li></li><li id="index:(1)--"><span class="invalid">(1)-- </span></li></ol>'], '']);
110
+ assert.deepStrictEqual(inspect(parser('1-1. 1')), [['<ol><li data-marker="1-1." id="index:1">1</li></ol>'], '']);
110
111
  });
111
112
 
112
113
  it('type', () => {
@@ -115,22 +116,23 @@ describe('Unit: parser/block/olist', () => {
115
116
  assert.deepStrictEqual(inspect(parser('I. ')), [['<ol type="I" data-type="upper-roman"><li></li></ol>'], '']);
116
117
  assert.deepStrictEqual(inspect(parser('A. ')), [['<ol type="A" data-type="upper-alpha"><li></li></ol>'], '']);
117
118
  assert.deepStrictEqual(inspect(parser('a.\n1.\nc')), [['<ol type="a" data-type="lower-alpha"><li></li><li data-marker="1."></li><li data-marker="c."></li></ol>'], '']);
119
+ assert.deepStrictEqual(inspect(parser('i. 1')), [['<ol type="i" data-type="lower-roman"><li id="index:1">1</li></ol>'], '']);
118
120
  });
119
121
 
120
122
  it('checkbox', () => {
121
123
  assert.deepStrictEqual(inspect(parser('1. [ ]')), [['<ol class="checklist"><li><span class="checkbox">☐</span></li></ol>'], '']);
122
124
  assert.deepStrictEqual(inspect(parser('1. [x]')), [['<ol class="checklist"><li><span class="checkbox">☑</span></li></ol>'], '']);
123
125
  assert.deepStrictEqual(inspect(parser('1. [X]')), [['<ol class="checklist"><li><span class="checkbox">☑</span></li></ol>'], '']);
124
- assert.deepStrictEqual(inspect(parser('1. [X] 1')), [['<ol class="checklist"><li><span class="checkbox">☑</span>1</li></ol>'], '']);
126
+ assert.deepStrictEqual(inspect(parser('1. [X] 1')), [['<ol class="checklist"><li id="index:1"><span class="checkbox">☑</span>1</li></ol>'], '']);
125
127
  });
126
128
 
127
129
  it('indexer', () => {
128
- assert.deepStrictEqual(inspect(parser('1. [#a]')), [['<ol><li><a class="index" href="#index:a">a</a></li></ol>'], '']);
129
- assert.deepStrictEqual(inspect(parser('1. a [#]')), [['<ol><li id="index:a">a<span class="indexer" data-index=""></span></li></ol>'], '']);
130
+ assert.deepStrictEqual(inspect(parser('1. [#a]')), [['<ol><li id="index:a"><a class="index" href="#index:a">a</a></li></ol>'], '']);
131
+ assert.deepStrictEqual(inspect(parser('1. a [#]')), [['<ol><li>a<span class="indexer" data-index=""></span></li></ol>'], '']);
130
132
  assert.deepStrictEqual(inspect(parser('1. a [#b]')), [['<ol><li id="index:b">a<span class="indexer" data-index="b"></span></li></ol>'], '']);
131
- assert.deepStrictEqual(inspect(parser('1. [ ] [#a]')), [['<ol class="checklist"><li><span class="checkbox">☐</span><a class="index" href="#index:a">a</a></li></ol>'], '']);
133
+ assert.deepStrictEqual(inspect(parser('1. [ ] [#a]')), [['<ol class="checklist"><li id="index:a"><span class="checkbox">☐</span><a class="index" href="#index:a">a</a></li></ol>'], '']);
132
134
  assert.deepStrictEqual(inspect(parser('1. [ ] a [#b]')), [['<ol class="checklist"><li id="index:b"><span class="checkbox">☐</span>a<span class="indexer" data-index="b"></span></li></ol>'], '']);
133
- assert.deepStrictEqual(inspect(parser('1. a [#]\n 1. c [#d]')), [['<ol><li id="index:a">a<span class="indexer" data-index=""></span><ol><li id="index:d">c<span class="indexer" data-index="d"></span></li></ol></li></ol>'], '']);
135
+ assert.deepStrictEqual(inspect(parser('1. a [#]\n 1. c [#d]')), [['<ol><li>a<span class="indexer" data-index=""></span><ol><li id="index:d">c<span class="indexer" data-index="d"></span></li></ol></li></ol>'], '']);
134
136
  assert.deepStrictEqual(inspect(parser('1. a [#b]\n 1. c [#d]')), [['<ol><li id="index:b">a<span class="indexer" data-index="b"></span><ol><li id="index:d">c<span class="indexer" data-index="d"></span></li></ol></li></ol>'], '']);
135
137
  });
136
138
 
@@ -17,7 +17,7 @@ export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
17
17
  ])));
18
18
 
19
19
  const opener = /^(?=\|\|+(?:$|\s))/;
20
- const unindent = (source: string) => source.replace(/(^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '$1');
20
+ const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
21
21
 
22
22
  const source: SidefenceParser.SourceParser = lazy(() => fmap(
23
23
  some(creation(1, false, union([
@@ -28,51 +28,51 @@ describe('Unit: parser/block/ulist', () => {
28
28
  // filled
29
29
  assert.deepStrictEqual(inspect(parser('- \\')), [['<ul><li></li></ul>'], '']);
30
30
  assert.deepStrictEqual(inspect(parser('- \\\n')), [['<ul><li></li></ul>'], '']);
31
- assert.deepStrictEqual(inspect(parser('- -')), [['<ul><li>-</li></ul>'], '']);
32
- assert.deepStrictEqual(inspect(parser('- -\n')), [['<ul><li>-</li></ul>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('- -')), [['<ul><li id="index:-">-</li></ul>'], '']);
32
+ assert.deepStrictEqual(inspect(parser('- -\n')), [['<ul><li id="index:-">-</li></ul>'], '']);
33
33
  });
34
34
 
35
35
  it('multiple', () => {
36
36
  // pending
37
37
  assert.deepStrictEqual(inspect(parser('-\n-')), [['<ul><li></li><li></li></ul>'], '']);
38
38
  // filled
39
- assert.deepStrictEqual(inspect(parser('- 1\n- 2')), [['<ul><li>1</li><li>2</li></ul>'], '']);
40
- assert.deepStrictEqual(inspect(parser('- 1\n- 2\n- 3')), [['<ul><li>1</li><li>2</li><li>3</li></ul>'], '']);
39
+ assert.deepStrictEqual(inspect(parser('- 1\n- 2')), [['<ul><li id="index:1">1</li><li id="index:2">2</li></ul>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('- 1\n- 2\n- 3')), [['<ul><li id="index:1">1</li><li id="index:2">2</li><li id="index:3">3</li></ul>'], '']);
41
41
  // invalid
42
- assert.deepStrictEqual(inspect(parser('-\n+')), [['<ul><li></li><li><span class="invalid">+</span></li></ul>'], '']);
43
- assert.deepStrictEqual(inspect(parser('-\n0')), [['<ul><li></li><li><span class="invalid">0</span></li></ul>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('-\n+')), [['<ul><li></li><li id="index:+"><span class="invalid">+</span></li></ul>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('-\n0')), [['<ul><li></li><li id="index:0"><span class="invalid">0</span></li></ul>'], '']);
44
44
  });
45
45
 
46
46
  it('nest', () => {
47
47
  assert.deepStrictEqual(inspect(parser('-\n -')), [['<ul><li><br><ul><li></li></ul></li></ul>'], '']);
48
- assert.deepStrictEqual(inspect(parser('- 1\n - 2')), [['<ul><li>1<ul><li>2</li></ul></li></ul>'], '']);
49
- assert.deepStrictEqual(inspect(parser('- 1\n - 2\n- 3')), [['<ul><li>1<ul><li>2</li></ul></li><li>3</li></ul>'], '']);
50
- assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li>1<ul><li>2</li><li>3</li></ul></li></ul>'], '']);
51
- assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li>1<ul><li>2<ul><li>3</li></ul></li></ul></li></ul>'], '']);
52
- assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li>1<ul><li>2</li></ul></li><li><span class="invalid"> - 3</span></li></ul>'], '']);
53
- assert.deepStrictEqual(inspect(parser('-\n -\n +\n -\n +\n+')), [['<ul><li><br><ul><li></li><li><span class="invalid">+</span></li><li></li><li><span class="invalid">+</span></li></ul></li><li><span class="invalid">+</span></li></ul>'], '']);
54
- assert.deepStrictEqual(inspect(parser('- 1\n + 2')), [['<ul><li>1<ul class="invalid"><li>2</li></ul></li></ul>'], '']);
55
- assert.deepStrictEqual(inspect(parser('- 1\n 0')), [['<ul><li>1<ol><li></li></ol></li></ul>'], '']);
56
- assert.deepStrictEqual(inspect(parser('- 1\n 0.')), [['<ul><li>1<ol><li></li></ol></li></ul>'], '']);
57
- assert.deepStrictEqual(inspect(parser('- 1\n 0. ')), [['<ul><li>1<ol><li></li></ol></li></ul>'], '']);
58
- assert.deepStrictEqual(inspect(parser('- 1\n 0. 2')), [['<ul><li>1<ol><li>2</li></ol></li></ul>'], '']);
59
- assert.deepStrictEqual(inspect(parser('- !http://host')), [['<ul><li>!<a class="url" href="http://host" target="_blank">http://host</a></li></ul>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('- 1\n - 2')), [['<ul><li id="index:1">1<ul><li id="index:2">2</li></ul></li></ul>'], '']);
49
+ assert.deepStrictEqual(inspect(parser('- 1\n - 2\n- 3')), [['<ul><li id="index:1">1<ul><li id="index:2">2</li></ul></li><li id="index:3">3</li></ul>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li id="index:1">1<ul><li id="index:2">2</li><li id="index:3">3</li></ul></li></ul>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li id="index:1">1<ul><li id="index:2">2<ul><li id="index:3">3</li></ul></li></ul></li></ul>'], '']);
52
+ assert.deepStrictEqual(inspect(parser('- 1\n - 2\n - 3')), [['<ul><li id="index:1">1<ul><li id="index:2">2</li></ul></li><li id="index:-_3"><span class="invalid"> - 3</span></li></ul>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('-\n -\n +\n -\n +\n+')), [['<ul><li><br><ul><li></li><li id="index:+"><span class="invalid">+</span></li><li></li><li id="index:+"><span class="invalid">+</span></li></ul></li><li id="index:+"><span class="invalid">+</span></li></ul>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('- 1\n + 2')), [['<ul><li id="index:1">1<ul class="invalid"><li>2</li></ul></li></ul>'], '']);
55
+ assert.deepStrictEqual(inspect(parser('- 1\n 0')), [['<ul><li id="index:1">1<ol><li></li></ol></li></ul>'], '']);
56
+ assert.deepStrictEqual(inspect(parser('- 1\n 0.')), [['<ul><li id="index:1">1<ol><li></li></ol></li></ul>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('- 1\n 0. ')), [['<ul><li id="index:1">1<ol><li></li></ol></li></ul>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('- 1\n 0. 2')), [['<ul><li id="index:1">1<ol><li id="index:2">2</li></ol></li></ul>'], '']);
59
+ assert.deepStrictEqual(inspect(parser('- !http://host')), [['<ul><li id="index:!http://host">!<a class="url" href="http://host" target="_blank">http://host</a></li></ul>'], '']);
60
60
  });
61
61
 
62
62
  it('checkbox', () => {
63
63
  assert.deepStrictEqual(inspect(parser('- [ ]')), [['<ul class="checklist"><li><span class="checkbox">☐</span></li></ul>'], '']);
64
64
  assert.deepStrictEqual(inspect(parser('- [x]')), [['<ul class="checklist"><li><span class="checkbox">☑</span></li></ul>'], '']);
65
65
  assert.deepStrictEqual(inspect(parser('- [X]')), [['<ul class="checklist"><li><span class="checkbox">☑</span></li></ul>'], '']);
66
- assert.deepStrictEqual(inspect(parser('- [X] 1')), [['<ul class="checklist"><li><span class="checkbox">☑</span>1</li></ul>'], '']);
66
+ assert.deepStrictEqual(inspect(parser('- [X] 1')), [['<ul class="checklist"><li id="index:1"><span class="checkbox">☑</span>1</li></ul>'], '']);
67
67
  });
68
68
 
69
69
  it('indexer', () => {
70
- assert.deepStrictEqual(inspect(parser('- [#a]')), [['<ul><li><a class="index" href="#index:a">a</a></li></ul>'], '']);
71
- assert.deepStrictEqual(inspect(parser('- a [#]')), [['<ul><li id="index:a">a<span class="indexer" data-index=""></span></li></ul>'], '']);
70
+ assert.deepStrictEqual(inspect(parser('- [#a]')), [['<ul><li id="index:a"><a class="index" href="#index:a">a</a></li></ul>'], '']);
71
+ assert.deepStrictEqual(inspect(parser('- a [#]')), [['<ul><li>a<span class="indexer" data-index=""></span></li></ul>'], '']);
72
72
  assert.deepStrictEqual(inspect(parser('- a [#b]')), [['<ul><li id="index:b">a<span class="indexer" data-index="b"></span></li></ul>'], '']);
73
- assert.deepStrictEqual(inspect(parser('- [ ] [#a]')), [['<ul class="checklist"><li><span class="checkbox">☐</span><a class="index" href="#index:a">a</a></li></ul>'], '']);
73
+ assert.deepStrictEqual(inspect(parser('- [ ] [#a]')), [['<ul class="checklist"><li id="index:a"><span class="checkbox">☐</span><a class="index" href="#index:a">a</a></li></ul>'], '']);
74
74
  assert.deepStrictEqual(inspect(parser('- [ ] a [#b]')), [['<ul class="checklist"><li id="index:b"><span class="checkbox">☐</span>a<span class="indexer" data-index="b"></span></li></ul>'], '']);
75
- assert.deepStrictEqual(inspect(parser('- a [#]\n - c [#d]')), [['<ul><li id="index:a">a<span class="indexer" data-index=""></span><ul><li id="index:d">c<span class="indexer" data-index="d"></span></li></ul></li></ul>'], '']);
75
+ assert.deepStrictEqual(inspect(parser('- a [#]\n - c [#d]')), [['<ul><li>a<span class="indexer" data-index=""></span><ul><li id="index:d">c<span class="indexer" data-index="d"></span></li></ul></li></ul>'], '']);
76
76
  assert.deepStrictEqual(inspect(parser('- a [#b]\n - c [#d]')), [['<ul><li id="index:b">a<span class="indexer" data-index="b"></span><ul><li id="index:d">c<span class="indexer" data-index="d"></span></li></ul></li></ul>'], '']);
77
77
  });
78
78
 
@@ -30,31 +30,29 @@ export function text(source: HTMLElement | DocumentFragment, optional = false):
30
30
  assert(source instanceof DocumentFragment || !source.matches('.indexer'));
31
31
  assert(source.querySelectorAll(':scope > .indexer').length <= 1);
32
32
  const indexer = source.querySelector(':scope > .indexer');
33
- if (!indexer && optional) return '';
34
33
  const index = indexer?.getAttribute('data-index');
35
34
  if (index) return index;
36
- assert(!source.querySelector('br'));
35
+ if (index === '' && optional) return '';
36
+ assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))'));
37
37
  const target = source.cloneNode(true) as typeof source;
38
38
  for (let es = target.querySelectorAll('code[data-src], .math[data-src], .comment, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'),
39
39
  len = es.length, i = 0; i < len; ++i) {
40
40
  const el = es[i];
41
41
  switch (el.tagName) {
42
42
  case 'CODE':
43
- define(el, el.getAttribute('data-src')!);
43
+ el.replaceWith(el.getAttribute('data-src')!);
44
44
  continue;
45
45
  case 'RT':
46
46
  case 'RP':
47
+ case 'BR':
47
48
  case 'UL':
48
49
  case 'OL':
49
50
  el.remove();
50
51
  continue;
51
- case 'BR':
52
- el.replaceWith('\n');
53
- continue;
54
52
  }
55
53
  switch (el.className) {
56
54
  case 'math':
57
- define(el, el.getAttribute('data-src')!);
55
+ el.replaceWith(el.getAttribute('data-src')!);
58
56
  continue;
59
57
  case 'comment':
60
58
  case 'checkbox':
@@ -20,33 +20,33 @@ describe('Unit: parser/inline/link', () => {
20
20
  });
21
21
 
22
22
  it('fishing', () => {
23
- assert.deepStrictEqual(inspect(parser('[http://host]{http://evil}')), undefined);
24
- assert.deepStrictEqual(inspect(parser('[\\http://host]{http://evil}')), undefined);
25
- assert.deepStrictEqual(inspect(parser('[https://host]{http://host}')), undefined);
26
- assert.deepStrictEqual(inspect(parser('[[]{http://host}.com]{http://host}')), undefined);
27
- assert.deepStrictEqual(inspect(parser('[[]{http://host/a}b]{http://host/ab}')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('[http://host]{http://evil}')), [['<a class="invalid">http://host</a>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('[\\http://host]{http://evil}')), [['<a class="invalid">http://host</a>'], '']);
25
+ assert.deepStrictEqual(inspect(parser('[https://host]{http://host}')), [['<a class="invalid">https://host</a>'], '']);
26
+ assert.deepStrictEqual(inspect(parser('[[]{http://host}.com]{http://host}')), [['<a class="invalid">[]{http://host}.com</a>'], '']);
27
+ assert.deepStrictEqual(inspect(parser('[[]{http://host/a}b]{http://host/ab}')), [['<a class="invalid">[]{http://host/a}b</a>'], '']);
28
28
  assert.deepStrictEqual(inspect(parser('{http%73://host}')), [['<a class="url" href="http%73://host">http%73://host</a>'], '']);
29
29
  assert.deepStrictEqual(inspect(parser('{http://a%C3%A1}')), [['<a class="url" href="http://a%C3%A1" target="_blank">http://a%C3%A1</a>'], '']);
30
- assert.deepStrictEqual(inspect(parser('[http://á]{http://evil}')), undefined);
31
- assert.deepStrictEqual(inspect(parser('[xxx://á]{http://evil}')), undefined);
32
- assert.deepStrictEqual(inspect(parser('[mailto:á]{http://evil}')), undefined);
33
- assert.deepStrictEqual(inspect(parser('[file:///]{http://evil}')), undefined);
34
- assert.deepStrictEqual(inspect(parser('[.http://á]{http://evil}')), undefined);
30
+ assert.deepStrictEqual(inspect(parser('[http://á]{http://evil}')), [['<a class="invalid">http://á</a>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('[xxx://á]{http://evil}')), [['<a class="invalid">xxx://á</a>'], '']);
32
+ assert.deepStrictEqual(inspect(parser('[mailto:á]{http://evil}')), [['<a class="invalid">mailto:á</a>'], '']);
33
+ assert.deepStrictEqual(inspect(parser('[file:///]{http://evil}')), [['<a class="invalid">file:///</a>'], '']);
34
+ assert.deepStrictEqual(inspect(parser('[.http://á]{http://evil}')), [['<a class="invalid">.http://á</a>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser('[0987654321]{tel:1234567890}')), [['<a class="invalid">0987654321</a>'], '']);
36
36
  assert.deepStrictEqual(inspect(parser('[1234567890-]{tel:1234567890}')), [['<a class="invalid">1234567890-</a>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser('[-1234567890]{tel:1234567890}')), [['<a class="invalid">-1234567890</a>'], '']);
38
38
  assert.deepStrictEqual(inspect(parser('[123456789a]{tel:1234567890}')), [['<a class="invalid">123456789a</a>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser('[1234567890]{tel:ttel:1234567890}')), [['<a class="invalid">1234567890</a>'], '']);
40
- //assert.deepStrictEqual(inspect(parser('[#a]{b}')), undefined);
41
- //assert.deepStrictEqual(inspect(parser('[\\#a]{b}')), undefined);
42
- //assert.deepStrictEqual(inspect(parser('[c #a]{b}')), undefined);
43
- //assert.deepStrictEqual(inspect(parser('[c \\#a]{b}')), undefined);
44
- //assert.deepStrictEqual(inspect(parser('[]{#a}')), [['<a class="link" href="#a">#a</a>'], '']);
45
- //assert.deepStrictEqual(inspect(parser('[@a]{b}')), undefined);
46
- //assert.deepStrictEqual(inspect(parser('[\\@a]{b}')), undefined);
47
- //assert.deepStrictEqual(inspect(parser('[c @a]{b}')), undefined);
48
- //assert.deepStrictEqual(inspect(parser('[c \\@a]{b}')), undefined);
49
- //assert.deepStrictEqual(inspect(parser('[]{@a}')), [['<a class="link" href="@a">@a</a>'], '']);
40
+ //assert.deepStrictEqual(inspect(parser('[#a]{b}')), [['<a class="link" href="b">#a</a>'], '']);
41
+ //assert.deepStrictEqual(inspect(parser('[\\#a]{b}')), [['<a class="link" href="b">#a</a>'], '']);
42
+ //assert.deepStrictEqual(inspect(parser('[c #a]{b}')), [['<a class="link" href="b">c #a</a>'], '']);
43
+ //assert.deepStrictEqual(inspect(parser('[c \\#a]{b}')), [['<a class="link" href="b">c #a</a>'], '']);
44
+ //assert.deepStrictEqual(inspect(parser('[]{#a}')), [['<a class="url" href="#a">#a</a>'], '']);
45
+ //assert.deepStrictEqual(inspect(parser('[@a]{b}')), [['<a class="link" href="b">@a</a>'], '']);
46
+ //assert.deepStrictEqual(inspect(parser('[\\@a]{b}')), [['<a class="link" href="b">@a</a>'], '']);
47
+ //assert.deepStrictEqual(inspect(parser('[c @a]{b}')), [['<a class="link" href="b">c @a</a>'], '']);
48
+ //assert.deepStrictEqual(inspect(parser('[c \\@a]{b}')), [['<a class="link" href="b">c @a</a>'], '']);
49
+ //assert.deepStrictEqual(inspect(parser('[]{@a}')), [['<a class="url" href="@a">@a</a>'], '']);
50
50
  });
51
51
 
52
52
  it('invalid', () => {
@@ -79,7 +79,7 @@ describe('Unit: parser/inline/link', () => {
79
79
  assert.deepStrictEqual(inspect(parser('[a\\\nb]{b}')), undefined);
80
80
  assert.deepStrictEqual(inspect(parser('[<wbr>]{b}')), undefined);
81
81
  assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), undefined);
82
- assert.deepStrictEqual(inspect(parser('[http://host]{http://host}')), undefined);
82
+ assert.deepStrictEqual(inspect(parser('[http://host]{http://host}')), [['<a class="invalid">http://host</a>'], '']);
83
83
  assert.deepStrictEqual(inspect(parser('[]{ttp://host}')), [['<a class="invalid">ttp://host</a>'], '']);
84
84
  //assert.deepStrictEqual(inspect(parser('[]{http://[::ffff:0:0%1]}')), [['<a class="invalid">http://[::ffff:0:0%1]</a>'], '']);
85
85
  //assert.deepStrictEqual(inspect(parser('[]{http://[::ffff:0:0/96]}')), [['<a class="invalid">http://[::ffff:0:0/96]</a>'], '']);
@@ -171,7 +171,11 @@ describe('Unit: parser/inline/link', () => {
171
171
  assert.deepStrictEqual(inspect(parser('[((a))]{b}')), [['<a class="link" href="b"><span class="paren">((a))</span></a>'], '']);
172
172
  assert.deepStrictEqual(inspect(parser('[[[a]]]{b}')), [['<a class="link" href="b">[[a]]</a>'], '']);
173
173
  assert.deepStrictEqual(inspect(parser('[!http://host]{/}')), [['<a class="link" href="/" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
174
- assert.deepStrictEqual(inspect(parser('[_a_]{b}')), [['<a class="link" href="b"><em>a</em></a>'], '']);
174
+ assert.deepStrictEqual(inspect(parser('[#a]{b}')), [['<a class="link" href="b">#a</a>'], '']);
175
+ assert.deepStrictEqual(inspect(parser('[@a]{b}')), [['<a class="link" href="b">@a</a>'], '']);
176
+ assert.deepStrictEqual(inspect(parser('[@a@b]{c}')), [['<a class="link" href="c">@a@b</a>'], '']);
177
+ assert.deepStrictEqual(inspect(parser('[a@b]{c}')), [['<a class="link" href="c">a@b</a>'], '']);
178
+ assert.deepStrictEqual(inspect(parser('[*a*]{b}')), [['<a class="link" href="b"><strong>a</strong></a>'], '']);
175
179
  });
176
180
 
177
181
  it('external', () => {
@@ -1,10 +1,9 @@
1
1
  import { MarkdownParser } from '../../../markdown';
2
2
  import { LinkParser } from '../inline';
3
- import { Result, eval, exec } from '../../combinator/data/parser';
4
- import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, state, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
3
+ import { Result } from '../../combinator/data/parser';
4
+ import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
- import { autolink as autolink_ } from '../autolink';
8
7
  import { unescsource, str } from '../source';
9
8
  import { Syntax, State } from '../context';
10
9
  import { trimNode } from '../visibility';
@@ -74,8 +73,6 @@ export const option: LinkParser.ParameterParser.OptionParser = union([
74
73
  fmap(str(/^[^\S\n]+[^\s{}]+/), opt => [` \\${opt.slice(1)}`]),
75
74
  ]);
76
75
 
77
- const autolink = state(State.autolink, false, state(State.shortcut, autolink_));
78
-
79
76
  function parse(
80
77
  content: (string | HTMLElement)[],
81
78
  params: string[],
@@ -85,13 +82,6 @@ function parse(
85
82
  assert(params.length > 0);
86
83
  assert(params.every(p => typeof p === 'string'));
87
84
  if (content.length !== 0 && trimNode(content).length === 0) return;
88
- content = defrag(content);
89
- for (let source = stringify(content); source;) {
90
- if (/^[a-z][0-9a-z]*(?:[-.][0-9a-z]+)*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i.test(source)) return;
91
- const result = autolink({ source, context });
92
- if (typeof eval(result, [])[0] === 'object') return;
93
- source = exec(result, '');
94
- }
95
85
  const INSECURE_URI = params.shift()!;
96
86
  assert(INSECURE_URI === INSECURE_URI.trim());
97
87
  assert(!INSECURE_URI.match(/\s/));
@@ -100,7 +90,7 @@ function parse(
100
90
  context.host?.href || location.href);
101
91
  const el = elem(
102
92
  INSECURE_URI,
103
- content,
93
+ defrag(content),
104
94
  uri,
105
95
  context.host?.origin || location.origin);
106
96
  if (el.className === 'invalid') return [[el], rest];
@@ -120,6 +110,10 @@ function elem(
120
110
  case 'https:':
121
111
  assert(uri.host);
122
112
  switch (true) {
113
+ case /[a-z][0-9]*:\/{0,2}\S/i.test(stringify(content)):
114
+ type = 'content';
115
+ message = 'URI must not be contained';
116
+ break;
123
117
  case INSECURE_URI.slice(0, 2) === '^/'
124
118
  && /\/\.\.?(?:\/|$)/.test(INSECURE_URI.slice(0, INSECURE_URI.search(/[?#]|$/))):
125
119
  type = 'argument';
@@ -165,6 +159,7 @@ function elem(
165
159
  type = 'content';
166
160
  message = 'Invalid content';
167
161
  }
162
+ break;
168
163
  }
169
164
  return html('a',
170
165
  {
@@ -205,7 +200,7 @@ function decode(uri: string): string {
205
200
  const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
206
201
  try {
207
202
  let path = decodeURI(uri.slice(origin.length));
208
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i.test(path)) {
203
+ if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
209
204
  path = uri.slice(origin.length);
210
205
  }
211
206
  uri = origin + path;
@@ -29,6 +29,7 @@ describe('Unit: parser/inline', () => {
29
29
  assert.deepStrictEqual(inspect(parser('*[*]')), [['*', '[', '*', ']'], '']);
30
30
  assert.deepStrictEqual(inspect(parser('*<*>')), [['<strong>&lt;</strong>', '>'], '']);
31
31
  assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<strong>a<sup class="annotation"><span>b</span></sup></strong>'], '']);
32
+ assert.deepStrictEqual(inspect(parser('++\na\n++\n~~\nb\n~~\nc')), [['<ins><br>a</ins>', '<br>', '<del><br>b</del>', '<br>', 'c'], '']);
32
33
  assert.deepStrictEqual(inspect(parser('``a`')), [['``', 'a', '`'], '']);
33
34
  assert.deepStrictEqual(inspect(parser('[@a]')), [['[', '<a class="account" href="/@a">@a</a>', ']'], '']);
34
35
  assert.deepStrictEqual(inspect(parser('[#1][#2]')), [['<a class="index" href="#index:1">1</a>', '<a class="index" href="#index:2">2</a>'], '']);
@@ -46,8 +47,8 @@ describe('Unit: parser/inline', () => {
46
47
  assert.deepStrictEqual(inspect(parser('[[#-1]a](b)')), [['[', '<a class="index" href="#index:-1">-1</a>', 'a', ']', '(', 'b', ')'], '']);
47
48
  assert.deepStrictEqual(inspect(parser('[#a]{b}')), [['<a class="index" href="#index:a">a</a>', '<a class="url" href="b">b</a>'], '']);
48
49
  assert.deepStrictEqual(inspect(parser('[@a]{b}')), [['<a class="link" href="b">@a</a>'], '']);
49
- assert.deepStrictEqual(inspect(parser('[http://host]{http://evil}')), [['[', '<a class="url" href="http://host" target="_blank">http://host</a>', ']', '<a class="url" href="http://evil" target="_blank">http://evil</a>'], '']);
50
- assert.deepStrictEqual(inspect(parser('[http://host]{http://host}')), [['[', '<a class="url" href="http://host" target="_blank">http://host</a>', ']', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
50
+ assert.deepStrictEqual(inspect(parser('[http://host]{http://evil}')), [['<a class="invalid">http://host</a>'], '']);
51
+ assert.deepStrictEqual(inspect(parser('[http://host]{http://host}')), [['<a class="invalid">http://host</a>'], '']);
51
52
  assert.deepStrictEqual(inspect(parser('[]{{a}}')), [['[', ']', '<span class="template">{{a}}</span>'], '']);
52
53
  assert.deepStrictEqual(inspect(parser('![]{{a}}')), [['!', '[', ']', '<span class="template">{{a}}</span>'], '']);
53
54
  assert.deepStrictEqual(inspect(parser('[\n]{a}')), [['[', '<br>', ']', '<a class="url" href="a">a</a>'], '']);
@@ -18,8 +18,6 @@ export function* figure(
18
18
  let base = '0';
19
19
  let bases: readonly string[] = base.split('.');
20
20
  let index: readonly string[] = bases;
21
- // Bug: Firefox
22
- //for (let defs = target.querySelectorAll(':scope > figure[data-label], :scope > h1, :scope > h2'), len = defs.length, i = 0; i < len; ++i) {
23
21
  for (
24
22
  let defs = target.querySelectorAll('figure[data-label], h1, h2'),
25
23
  len = defs.length, i = 0; i < len; ++i) {
@@ -8,8 +8,6 @@ export function* footnote(
8
8
  opts: { readonly id?: string; } = {},
9
9
  bottom: Node | null = null,
10
10
  ): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
11
- // Bug: Firefox
12
- //target.querySelectorAll(`:scope > .annotations`).forEach(el => el.remove());
13
11
  for (let es = target.querySelectorAll(`.annotations`),
14
12
  len = es.length, i = 0; i < len; ++i) {
15
13
  const el = es[i];
@@ -40,8 +38,6 @@ function build(
40
38
  const defs = new Map<string, HTMLLIElement>();
41
39
  const buffer = new MultiQueue<string, HTMLElement>();
42
40
  const titles = new Map<string, string>();
43
- // Bug: Firefox
44
- //const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
45
41
  const splitters: Element[] = [];
46
42
  for (let es = target.querySelectorAll(splitter ?? '_'),
47
43
  len = es.length, i = 0; i < len; ++i) {
package/src/util/toc.ts CHANGED
@@ -1,8 +1,6 @@
1
1
  import { push } from 'spica/array';
2
2
  import { html } from 'typed-dom/dom';
3
3
 
4
- // Bug: Firefox
5
- //const selector = `:scope > :is(h1, h2, h3, h4, h5, h6, aside.aside)[id]`;
6
4
  const selector = ':is(h1, h2, h3, h4, h5, h6, aside.aside)[id]';
7
5
 
8
6
  export function toc(source: DocumentFragment | HTMLElement | ShadowRoot): HTMLUListElement {