securemark 0.264.0 → 0.266.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/index.js +44 -58
  3. package/index.d.ts +2 -1
  4. package/package.json +1 -1
  5. package/src/combinator/data/parser/some.ts +2 -1
  6. package/src/parser/api/bind.test.ts +17 -17
  7. package/src/parser/api/bind.ts +1 -0
  8. package/src/parser/api/normalize.ts +1 -1
  9. package/src/parser/api/parse.test.ts +6 -6
  10. package/src/parser/api/parse.ts +2 -1
  11. package/src/parser/block/blockquote.ts +1 -1
  12. package/src/parser/block/dlist.test.ts +34 -34
  13. package/src/parser/block/extension/aside.test.ts +3 -3
  14. package/src/parser/block/extension/aside.ts +2 -4
  15. package/src/parser/block/extension/figure.test.ts +2 -2
  16. package/src/parser/block/heading.test.ts +47 -47
  17. package/src/parser/block/olist.test.ts +30 -28
  18. package/src/parser/block/reply/cite.test.ts +1 -1
  19. package/src/parser/block/sidefence.ts +1 -1
  20. package/src/parser/block/ulist.test.ts +26 -26
  21. package/src/parser/inline/extension/index.test.ts +48 -48
  22. package/src/parser/inline/extension/index.ts +1 -1
  23. package/src/parser/inline/extension/indexee.ts +19 -18
  24. package/src/parser/inline/extension/indexer.ts +1 -1
  25. package/src/parser/inline/link.test.ts +26 -22
  26. package/src/parser/inline/link.ts +9 -14
  27. package/src/parser/inline/mark.test.ts +9 -9
  28. package/src/parser/inline/mark.ts +1 -1
  29. package/src/parser/inline.test.ts +7 -6
  30. package/src/parser/processor/figure.test.ts +19 -19
  31. package/src/parser/processor/figure.ts +0 -2
  32. package/src/parser/processor/footnote.test.ts +66 -66
  33. package/src/parser/processor/footnote.ts +11 -15
  34. package/src/util/toc.test.ts +28 -28
  35. package/src/util/toc.ts +0 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.266.0
4
+
5
+ - Change index schemas.
6
+ - Fix footnote processing.
7
+
8
+ ## 0.265.0
9
+
10
+ - Change ulist and olist parsers to index list items.
11
+ - Change link parser to accept autolinks.
12
+
3
13
  ## 0.264.0
4
14
 
5
15
  - 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.266.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"));
@@ -3908,6 +3908,7 @@ function bind(target, settings) {
3908
3908
  })
3909
3909
  };
3910
3910
 
3911
+ if (context.id?.includes(':')) throw new Error('ID must not contain ":"');
3911
3912
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
3912
3913
  const blocks = [];
3913
3914
  const adds = [];
@@ -4151,7 +4152,7 @@ function format(source) {
4151
4152
  return source.replace(/\r\n?/g, '\n');
4152
4153
  }
4153
4154
  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);
4155
+ 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
4156
  }
4156
4157
  // https://dev.w3.org/html5/html-author/charref
4157
4158
  // https://en.wikipedia.org/wiki/Whitespace_character
@@ -4224,7 +4225,8 @@ const footnote_1 = __webpack_require__(7529);
4224
4225
  const url_1 = __webpack_require__(2261);
4225
4226
  const dom_1 = __webpack_require__(3252);
4226
4227
  function parse(source, opts = {}, context) {
4227
- if (!(0, segment_1.validate)(source, segment_1.MAX_SEGMENT_SIZE)) throw new Error(`Too large input over ${segment_1.MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.`);
4228
+ if (!(0, segment_1.validate)(source, segment_1.MAX_SEGMENT_SIZE)) throw new Error(`Too large input over ${segment_1.MAX_SEGMENT_SIZE.toLocaleString('en')} bytes`);
4229
+ if (context?.id?.includes(':')) throw new Error('ID must not contain ":"');
4228
4230
  const url = (0, header_2.headers)(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
4229
4231
  source = !context ? (0, normalize_1.normalize)(source) : source;
4230
4232
  context = {
@@ -4263,7 +4265,7 @@ exports.parse = parse;
4263
4265
 
4264
4266
  /***/ }),
4265
4267
 
4266
- /***/ 6578:
4268
+ /***/ 7185:
4267
4269
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
4268
4270
 
4269
4271
  "use strict";
@@ -4366,7 +4368,7 @@ Object.defineProperty(exports, "__esModule", ({
4366
4368
  }));
4367
4369
  exports.blockquote = exports.segment = void 0;
4368
4370
  const combinator_1 = __webpack_require__(2087);
4369
- const autolink_1 = __webpack_require__(6578);
4371
+ const autolink_1 = __webpack_require__(7185);
4370
4372
  const source_1 = __webpack_require__(6743);
4371
4373
  const parse_1 = __webpack_require__(5013);
4372
4374
  const dom_1 = __webpack_require__(3252);
@@ -4374,7 +4376,7 @@ exports.segment = (0, combinator_1.block)((0, combinator_1.validate)(['!>', '>']
4374
4376
  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
4377
  const opener = /^(?=>>+(?:$|\s))/;
4376
4378
  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');
4379
+ const unindent = source => source.replace(/(?<=^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '');
4378
4380
  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
4381
  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
4382
  source,
@@ -4406,7 +4408,7 @@ Object.defineProperty(exports, "__esModule", ({
4406
4408
  exports.codeblock = exports.segment_ = exports.segment = void 0;
4407
4409
  const parser_1 = __webpack_require__(6728);
4408
4410
  const combinator_1 = __webpack_require__(2087);
4409
- const autolink_1 = __webpack_require__(6578);
4411
+ const autolink_1 = __webpack_require__(7185);
4410
4412
  const dom_1 = __webpack_require__(3252);
4411
4413
  const opener = /^(`{3,})(?!`)([^\n]*)(?:$|\n)/;
4412
4414
  const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/i;
@@ -4539,8 +4541,6 @@ exports.aside = (0, combinator_1.block)((0, combinator_1.validate)('~~~', (0, co
4539
4541
  references
4540
4542
  }
4541
4543
  }, context);
4542
- // Bug: Firefox
4543
- //const heading = document.querySelector(':scope > h1:first-child');
4544
4544
  const heading = 'H1 H2 H3 H4 H5 H6'.split(' ').includes(document.firstElementChild?.tagName) && document.firstElementChild;
4545
4545
  if (!heading) return [(0, dom_1.html)('pre', {
4546
4546
  class: 'invalid',
@@ -4550,7 +4550,7 @@ exports.aside = (0, combinator_1.block)((0, combinator_1.validate)('~~~', (0, co
4550
4550
  'data-invalid-message': 'Missing the title at the first line'
4551
4551
  }, `${opener}${body}${closer}`)];
4552
4552
  return [(0, dom_1.html)('aside', {
4553
- id: (0, indexee_1.identity)((0, indexee_1.text)(heading)),
4553
+ id: (0, indexee_1.identity)(context.id, (0, indexee_1.text)(heading)),
4554
4554
  class: 'aside'
4555
4555
  }, [document, (0, dom_1.html)('h2', 'References'), references])];
4556
4556
  })));
@@ -5455,7 +5455,7 @@ const parser_1 = __webpack_require__(6728);
5455
5455
  const combinator_1 = __webpack_require__(2087);
5456
5456
  const math_1 = __webpack_require__(8946);
5457
5457
  const source_1 = __webpack_require__(6743);
5458
- const autolink_1 = __webpack_require__(6578);
5458
+ const autolink_1 = __webpack_require__(7185);
5459
5459
  const dom_1 = __webpack_require__(3252);
5460
5460
  exports.syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
5461
5461
  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 +5516,7 @@ Object.defineProperty(exports, "__esModule", ({
5516
5516
  }));
5517
5517
  exports.sidefence = void 0;
5518
5518
  const combinator_1 = __webpack_require__(2087);
5519
- const autolink_1 = __webpack_require__(6578);
5519
+ const autolink_1 = __webpack_require__(7185);
5520
5520
  const source_1 = __webpack_require__(6743);
5521
5521
  const dom_1 = __webpack_require__(3252);
5522
5522
  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 +5526,7 @@ exports.sidefence = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, com
5526
5526
  'data-invalid-message': 'Reserved syntax'
5527
5527
  })])));
5528
5528
  const opener = /^(?=\|\|+(?:$|\s))/;
5529
- const unindent = source => source.replace(/(^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '$1');
5529
+ const unindent = source => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
5530
5530
  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
5531
 
5532
5532
  /***/ }),
@@ -5687,7 +5687,7 @@ const insertion_1 = __webpack_require__(2945);
5687
5687
  const deletion_1 = __webpack_require__(7501);
5688
5688
  const mark_1 = __webpack_require__(2480);
5689
5689
  const emphasis_1 = __webpack_require__(3867);
5690
- const strong_1 = __webpack_require__(8072);
5690
+ const strong_1 = __webpack_require__(6578);
5691
5691
  const code_1 = __webpack_require__(5771);
5692
5692
  const media_1 = __webpack_require__(1303);
5693
5693
  const htmlentity_1 = __webpack_require__(1562);
@@ -6106,7 +6106,7 @@ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0
6106
6106
  }, el.childNodes)])));
6107
6107
  const signature = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combinator_1.fmap)((0, combinator_1.open)('|', (0, visibility_1.startTight)((0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'))), ns => [(0, dom_1.html)('span', {
6108
6108
  class: 'indexer',
6109
- 'data-index': (0, indexee_1.identity)(ns.join('')).slice(6)
6109
+ 'data-index': (0, indexee_1.identity)(undefined, ns.join('')).slice(7)
6110
6110
  })])));
6111
6111
  const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(8, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true)])));
6112
6112
 
@@ -6128,46 +6128,46 @@ function indexee(parser, optional) {
6128
6128
  return (0, combinator_1.fmap)(parser, ([el], _, {
6129
6129
  id
6130
6130
  }) => [(0, dom_1.define)(el, {
6131
- id: id !== '' && identity(text(el, optional)) || undefined
6131
+ id: identity(id, text(el, optional))
6132
6132
  })]);
6133
6133
  }
6134
6134
  exports.indexee = indexee;
6135
- function identity(text, name = 'index') {
6135
+ function identity(id, text, name = 'index') {
6136
+ if (id === '') return undefined;
6136
6137
  text &&= text.trim().replace(/\s+/g, '_');
6137
- if (text.length <= 100) return text && `${name}:${text}`;
6138
+ if (text === '') return undefined;
6139
+ if (text.length <= 100) return `${name}:${id ?? ''}:${text}`;
6138
6140
  switch (name) {
6139
6141
  case 'index':
6140
- return `${name}:${text.slice(0, 97)}...`;
6142
+ return `${name}:${id ?? ''}:${text.slice(0, 97)}...`;
6141
6143
  case 'mark':
6142
- return `${name}:${text.slice(0, 50)}...${text.slice(-47)}`;
6144
+ return `${name}:${id ?? ''}:${text.slice(0, 50)}...${text.slice(-47)}`;
6143
6145
  }
6144
6146
  }
6145
6147
  exports.identity = identity;
6146
6148
  function text(source, optional = false) {
6147
6149
  const indexer = source.querySelector(':scope > .indexer');
6148
- if (!indexer && optional) return '';
6149
6150
  const index = indexer?.getAttribute('data-index');
6150
6151
  if (index) return index;
6152
+ if (index === '' && optional) return '';
6151
6153
  const target = source.cloneNode(true);
6152
6154
  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
6155
  const el = es[i];
6154
6156
  switch (el.tagName) {
6155
6157
  case 'CODE':
6156
- (0, dom_1.define)(el, el.getAttribute('data-src'));
6158
+ el.replaceWith(el.getAttribute('data-src'));
6157
6159
  continue;
6158
6160
  case 'RT':
6159
6161
  case 'RP':
6162
+ case 'BR':
6160
6163
  case 'UL':
6161
6164
  case 'OL':
6162
6165
  el.remove();
6163
6166
  continue;
6164
- case 'BR':
6165
- el.replaceWith('\n');
6166
- continue;
6167
6167
  }
6168
6168
  switch (el.className) {
6169
6169
  case 'math':
6170
- (0, dom_1.define)(el, el.getAttribute('data-src'));
6170
+ el.replaceWith(el.getAttribute('data-src'));
6171
6171
  continue;
6172
6172
  case 'comment':
6173
6173
  case 'checkbox':
@@ -6204,7 +6204,7 @@ exports.indexer = (0, combinator_1.creation)((0, combinator_1.fmap)((0, combinat
6204
6204
  // Indexer is invisible but invalids must be visible.
6205
6205
  ([el]) => el.getElementsByClassName('invalid').length === 0), ([el]) => [(0, dom_1.html)('span', {
6206
6206
  class: 'indexer',
6207
- 'data-index': el.getAttribute('href').slice(7)
6207
+ 'data-index': el.getAttribute('href').slice(1).replace(/^\w+:\w*:/, '')
6208
6208
  })]));
6209
6209
 
6210
6210
  /***/ }),
@@ -6411,11 +6411,9 @@ Object.defineProperty(exports, "__esModule", ({
6411
6411
  value: true
6412
6412
  }));
6413
6413
  exports.resolve = exports.option = exports.uri = exports.unsafelink = exports.link = void 0;
6414
- const parser_1 = __webpack_require__(6728);
6415
6414
  const combinator_1 = __webpack_require__(2087);
6416
6415
  const inline_1 = __webpack_require__(1160);
6417
6416
  const html_1 = __webpack_require__(5994);
6418
- const autolink_1 = __webpack_require__(6578);
6419
6417
  const source_1 = __webpack_require__(6743);
6420
6418
  const visibility_1 = __webpack_require__(7618);
6421
6419
  const util_1 = __webpack_require__(9437);
@@ -6433,22 +6431,11 @@ const medialink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(16 /
6433
6431
  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
6432
  exports.uri = (0, combinator_1.union)([(0, combinator_1.open)(/^[^\S\n]+/, (0, source_1.str)(/^\S+/)), (0, source_1.str)(/^[^\s{}]+/)]);
6435
6433
  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
6434
  function parse(content, params, rest, context) {
6438
6435
  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
6436
  const INSECURE_URI = params.shift();
6450
6437
  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);
6438
+ const el = elem(INSECURE_URI, (0, dom_1.defrag)(content), uri, context.host?.origin || location.origin);
6452
6439
  if (el.className === 'invalid') return [[el], rest];
6453
6440
  return [[(0, dom_1.define)(el, (0, html_1.attributes)('link', [], optspec, params))], rest];
6454
6441
  }
@@ -6459,6 +6446,10 @@ function elem(INSECURE_URI, content, uri, origin) {
6459
6446
  case 'http:':
6460
6447
  case 'https:':
6461
6448
  switch (true) {
6449
+ case /[a-z][0-9]*:\/{0,2}\S/i.test((0, util_1.stringify)(content)):
6450
+ type = 'content';
6451
+ message = 'URI must not be contained';
6452
+ break;
6462
6453
  case INSECURE_URI.slice(0, 2) === '^/' && /\/\.\.?(?:\/|$)/.test(INSECURE_URI.slice(0, INSECURE_URI.search(/[?#]|$/))):
6463
6454
  type = 'argument';
6464
6455
  message = 'Dot-segments cannot be used in subresource paths';
@@ -6484,6 +6475,7 @@ function elem(INSECURE_URI, content, uri, origin) {
6484
6475
  type = 'content';
6485
6476
  message = 'Invalid content';
6486
6477
  }
6478
+ break;
6487
6479
  }
6488
6480
  return (0, dom_1.html)('a', {
6489
6481
  class: 'invalid',
@@ -6512,7 +6504,7 @@ function decode(uri) {
6512
6504
  const origin = uri.match(/^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i)?.[0] ?? '';
6513
6505
  try {
6514
6506
  let path = decodeURI(uri.slice(origin.length));
6515
- if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:(?:\/{0,2}[^/?#\s]+|\/\/(?=[/]))/i.test(path)) {
6507
+ if (!origin && /^[a-z](?:[-.](?=\w)|[0-9a-z])*:\/{0,2}\S/i.test(path)) {
6516
6508
  path = uri.slice(origin.length);
6517
6509
  }
6518
6510
  uri = origin + path;
@@ -6545,7 +6537,7 @@ exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, sourc
6545
6537
  }) => {
6546
6538
  const el = (0, dom_1.html)('mark', (0, dom_1.defrag)(bs));
6547
6539
  (0, dom_1.define)(el, {
6548
- id: id !== '' && (0, indexee_1.identity)((0, indexee_1.text)(el), 'mark') || undefined
6540
+ id: (0, indexee_1.identity)(id, (0, indexee_1.text)(el), 'mark')
6549
6541
  });
6550
6542
  return [[el, (0, dom_1.html)('a', {
6551
6543
  href: el.id ? `#${el.id}` : undefined
@@ -6831,7 +6823,7 @@ exports.shortmedia = (0, combinator_1.rewrite)((0, combinator_1.constraint)(8 /*
6831
6823
 
6832
6824
  /***/ }),
6833
6825
 
6834
- /***/ 8072:
6826
+ /***/ 6578:
6835
6827
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
6836
6828
 
6837
6829
  "use strict";
@@ -6894,8 +6886,6 @@ function* figure(target, footnotes, opts = {}) {
6894
6886
  let base = '0';
6895
6887
  let bases = base.split('.');
6896
6888
  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
6889
  for (let defs = target.querySelectorAll('figure[data-label], h1, h2'), len = defs.length, i = 0; i < len; ++i) {
6900
6890
  yield;
6901
6891
  const def = defs[i];
@@ -7056,8 +7046,6 @@ const indexee_1 = __webpack_require__(1269);
7056
7046
  const queue_1 = __webpack_require__(4934);
7057
7047
  const dom_1 = __webpack_require__(3252);
7058
7048
  function* footnote(target, footnotes, opts = {}, bottom = null) {
7059
- // Bug: Firefox
7060
- //target.querySelectorAll(`:scope > .annotations`).forEach(el => el.remove());
7061
7049
  for (let es = target.querySelectorAll(`.annotations`), len = es.length, i = 0; i < len; ++i) {
7062
7050
  const el = es[i];
7063
7051
  el.parentNode === target && el.remove();
@@ -7076,8 +7064,6 @@ function build(syntax, marker, splitter) {
7076
7064
  const defs = new Map();
7077
7065
  const buffer = new queue_1.MultiQueue();
7078
7066
  const titles = new Map();
7079
- // Bug: Firefox
7080
- //const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
7081
7067
  const splitters = [];
7082
7068
  for (let es = target.querySelectorAll(splitter ?? '_'), len = es.length, i = 0; i < len; ++i) {
7083
7069
  const el = es[i];
@@ -7089,16 +7075,18 @@ function build(syntax, marker, splitter) {
7089
7075
  for (let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`), len = refs.length, i = 0; i < len; ++i) {
7090
7076
  yield;
7091
7077
  const ref = refs[i];
7092
- while (+splitters[0]?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
7078
+ while (splitters.length > 0 && splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
7093
7079
  if (defs.size > 0) {
7094
7080
  total += defs.size;
7095
7081
  yield* proc(defs, target.insertBefore((0, dom_1.html)('ol', {
7096
7082
  class: `${syntax}s`
7097
- }), splitters[0] ?? null));
7083
+ }), splitters[0]));
7084
+ } else if (splitters.length % 100 === 0) {
7085
+ yield;
7098
7086
  }
7099
7087
  splitters.shift();
7100
7088
  }
7101
- const identifier = `${+!ref.querySelector('.label')}:${ref.getAttribute('data-abbr') || '_' + ref.firstElementChild.innerHTML}`;
7089
+ const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild.innerHTML}`;
7102
7090
  const abbr = ref.getAttribute('data-abbr') || undefined;
7103
7091
  const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
7104
7092
  style ??= abbr ? 'abbr' : 'count';
@@ -7122,13 +7110,13 @@ function build(syntax, marker, splitter) {
7122
7110
  } else {
7123
7111
  ref.lastChild?.remove();
7124
7112
  }
7125
- const title = false || titles.get(identifier) || +identifier[0] && ref.title || (0, indexee_1.text)(content).trim() || content.textContent.trim() || undefined;
7113
+ const title = titles.get(identifier) || (0, indexee_1.text)(content).trim() || undefined;
7126
7114
  title ? !titles.has(identifier) && titles.set(identifier, title) : buffer.set(identifier, ref);
7127
7115
  const blank = !!abbr && !content.firstChild;
7128
7116
  const refIndex = ++count;
7129
- const refId = opts.id !== '' ? ref.id || `${syntax}:${opts.id ? `${opts.id}:` : ''}ref:${refIndex}` : undefined;
7117
+ const refId = opts.id !== '' ? `${syntax}:${opts.id ?? ''}:ref:${refIndex}` : undefined;
7130
7118
  const def = false || defs.get(identifier) || defs.set(identifier, (0, dom_1.html)('li', {
7131
- id: opts.id !== '' ? `${syntax}:${opts.id ? `${opts.id}:` : ''}def:${total + defs.size + 1}` : undefined,
7119
+ id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${total + defs.size + 1}` : undefined,
7132
7120
  'data-marker': !footnote ? marker(total + defs.size + 1, abbr) : undefined
7133
7121
  }, [content.cloneNode(true), (0, dom_1.html)('sup')])).get(identifier);
7134
7122
  if (title && !blank && def.childNodes.length === 1) {
@@ -8331,8 +8319,6 @@ Object.defineProperty(exports, "__esModule", ({
8331
8319
  exports.toc = void 0;
8332
8320
  const array_1 = __webpack_require__(8112);
8333
8321
  const dom_1 = __webpack_require__(3252);
8334
- // Bug: Firefox
8335
- //const selector = `:scope > :is(h1, h2, h3, h4, h5, h6, aside.aside)[id]`;
8336
8322
  const selector = ':is(h1, h2, h3, h4, h5, h6, aside.aside)[id]';
8337
8323
  function toc(source) {
8338
8324
  const hs = [];
package/index.d.ts CHANGED
@@ -28,7 +28,8 @@ export type ParserOptions = Omit<Partial<ParserSettings>, 'chunk'>;
28
28
  export interface ParserSettings {
29
29
  // Host URL.
30
30
  readonly host?: URL;
31
- // Id of comments and timelines.
31
+ // ID of comments and timelines.
32
+ // Must not contain ":".
32
33
  readonly id?: string;
33
34
  // For editing.
34
35
  readonly caches?: Partial<Caches>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.264.0",
3
+ "version": "0.266.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);
@@ -122,7 +122,7 @@ describe('Unit: parser/api/bind', () => {
122
122
  });
123
123
 
124
124
  it('complex', () => {
125
- assert.deepStrictEqual(inspect(bind(html('div'), cfgs).parse('# a\n# b')), ['<h1 id="index:a">a</h1>', '<h1 id="index:b">b</h1>']);
125
+ assert.deepStrictEqual(inspect(bind(html('div'), cfgs).parse('# a\n# b')), ['<h1 id="index::a">a</h1>', '<h1 id="index::b">b</h1>']);
126
126
  });
127
127
 
128
128
  it('normalize', () => {
@@ -158,10 +158,10 @@ describe('Unit: parser/api/bind', () => {
158
158
  assert(el.innerHTML === '<p>1</p><p>2</p><p>4</p>');
159
159
  [...update('')];
160
160
  assert(el.innerHTML === '');
161
- assert.deepStrictEqual(inspect(update('# a\n# b'), 1), ['<h1 id="index:a">a</h1>']);
162
- assert(el.innerHTML === '<h1 id="index:a">a</h1>');
163
- assert.deepStrictEqual(inspect(update('# a\n# b'), 2), ['<h1 id="index:b">b</h1>']);
164
- assert(el.innerHTML === '<h1 id="index:a">a</h1><h1 id="index:b">b</h1>');
161
+ assert.deepStrictEqual(inspect(update('# a\n# b'), 1), ['<h1 id="index::a">a</h1>']);
162
+ assert(el.innerHTML === '<h1 id="index::a">a</h1>');
163
+ assert.deepStrictEqual(inspect(update('# a\n# b'), 2), ['<h1 id="index::b">b</h1>']);
164
+ assert(el.innerHTML === '<h1 id="index::a">a</h1><h1 id="index::b">b</h1>');
165
165
  });
166
166
 
167
167
  it('chunk', () => {
@@ -192,38 +192,38 @@ describe('Unit: parser/api/bind', () => {
192
192
  [...el.children].map(el => el.outerHTML),
193
193
  [
194
194
  html('p', [
195
- html('sup', { class: "reference", id: "reference:ref:1", title: "1" }, [
195
+ html('sup', { class: "reference", id: "reference::ref:1", title: "1" }, [
196
196
  html('span', { hidden: '' }, '1'),
197
- html('a', { href: "#reference:def:1" }, '[1]'),
197
+ html('a', { href: "#reference::def:1" }, '[1]'),
198
198
  ]),
199
199
  ]).outerHTML,
200
200
  html('p', [
201
- html('sup', { class: "reference", id: "reference:ref:2", title: "2" }, [
201
+ html('sup', { class: "reference", id: "reference::ref:2", title: "2" }, [
202
202
  html('span', { hidden: '' }, '2'),
203
- html('a', { href: "#reference:def:2" }, '[2]'),
203
+ html('a', { href: "#reference::def:2" }, '[2]'),
204
204
  ]),
205
205
  ]).outerHTML,
206
206
  html('p', [
207
- html('sup', { class: "reference", id: "reference:ref:3", title: "3" }, [
207
+ html('sup', { class: "reference", id: "reference::ref:3", title: "3" }, [
208
208
  html('span', { hidden: '' }, '3'),
209
- html('a', { href: "#reference:def:3" }, '[3]'),
209
+ html('a', { href: "#reference::def:3" }, '[3]'),
210
210
  ]),
211
211
  ]).outerHTML,
212
212
  ]);
213
213
  assert.deepStrictEqual(
214
214
  cfgs.footnotes.references?.outerHTML,
215
215
  html('ol', [
216
- html('li', { id: 'reference:def:1' }, [
216
+ html('li', { id: 'reference::def:1' }, [
217
217
  '1',
218
- html('sup', [html('a', { href: '#reference:ref:1' }, '^1')]),
218
+ html('sup', [html('a', { href: '#reference::ref:1' }, '^1')]),
219
219
  ]),
220
- html('li', { id: 'reference:def:2' }, [
220
+ html('li', { id: 'reference::def:2' }, [
221
221
  '2',
222
- html('sup', [html('a', { href: '#reference:ref:2' }, '^2')]),
222
+ html('sup', [html('a', { href: '#reference::ref:2' }, '^2')]),
223
223
  ]),
224
- html('li', { id: 'reference:def:3' }, [
224
+ html('li', { id: 'reference::def:3' }, [
225
225
  '3',
226
- html('sup', [html('a', { href: '#reference:ref:3' }, '^3')]),
226
+ html('sup', [html('a', { href: '#reference::ref:3' }, '^3')]),
227
227
  ]),
228
228
  ]).outerHTML);
229
229
  assert.throws(() => update('').next());
@@ -26,6 +26,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
26
26
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
27
27
  memo: new Memo({ targets: State.backtrackers }),
28
28
  };
29
+ if (context.id?.includes(':')) throw new Error('ID must not contain ":"');
29
30
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
30
31
  assert(!settings.id);
31
32
  type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
@@ -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
@@ -123,10 +123,10 @@ describe('Unit: parser/api/parse', () => {
123
123
  '<p><a class="channel" href="https://domain/@a?ch=b" target="_blank">@domain/a#b</a></p>',
124
124
  '<p><a class="hashtag" href="https://source/hashtags/a" target="_blank">#a</a></p>',
125
125
  '<p><a class="hashtag" href="https://domain/hashtags/a" target="_blank">#domain/a</a></p>',
126
- '<p><a class="index" href="#index:a">a</a></p>',
126
+ '<p><a class="index" href="#index::a">a</a></p>',
127
127
  '<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>',
128
128
  '<p><a class="label" data-label="$-a" href="#label:$-a">(1)</a></p>',
129
- '<p><sup class="annotation" id="annotation:ref:1" title="a"><span hidden="">a</span><a href="#annotation:def:1">*1</a></sup></p>',
129
+ '<p><sup class="annotation" id="annotation::ref:1" title="a"><span hidden="">a</span><a href="#annotation::def:1">*1</a></sup></p>',
130
130
  '<p><a class="url" href="https://source/x/a" target="_blank">a</a></p>',
131
131
  '<p><a class="url" href="https://source/a" target="_blank">/a</a></p>',
132
132
  '<p><a class="url" href="/z/a">^/a</a></p>',
@@ -137,7 +137,7 @@ describe('Unit: parser/api/parse', () => {
137
137
  '<p><a href="https://source/x/a" target="_blank"><img class="media" data-src="https://source/x/a" alt=""></a></p>',
138
138
  '<p><a href="/z/a" target="_blank"><img class="media" data-src="/z/a" alt=""></a></p>',
139
139
  '<p><a href="https://source/a" target="_blank"><img class="media" data-src="https://source/a" alt=""></a></p>',
140
- '<ol class="annotations"><li id="annotation:def:1" data-marker="*1">a<sup><a href="#annotation:ref:1">^1</a></sup></li></ol>',
140
+ '<ol class="annotations"><li id="annotation::def:1" data-marker="*1">a<sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
141
141
  ]);
142
142
  assert.deepStrictEqual(
143
143
  [...parse([
@@ -209,12 +209,12 @@ describe('Unit: parser/api/parse', () => {
209
209
  [...parse('$-a\n$$\n$$\n\n(($-a[[b]][[c_d_]]))', { footnotes }).children].map(el => el.outerHTML),
210
210
  [
211
211
  '<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>',
212
- '<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>',
213
- '<ol class="annotations"><li id="annotation:def:1" data-marker="*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><sup><a href="#annotation:ref:1">^1</a></sup></li></ol>',
212
+ '<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>',
213
+ '<ol class="annotations"><li id="annotation::def:1" data-marker="*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><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>',
214
214
  ]);
215
215
  assert.deepStrictEqual(
216
216
  footnotes.references.outerHTML,
217
- '<ol><li id="reference:def:1">b<sup><a href="#reference:ref:1">^1</a></sup></li><li id="reference:def:2">c<em>d</em><sup><a href="#reference:ref:2">^2</a></sup></li></ol>');
217
+ '<ol><li id="reference::def:1">b<sup><a href="#reference::ref:1">^1</a></sup></li><li id="reference::def:2">c<em>d</em><sup><a href="#reference::ref:2">^2</a></sup></li></ol>');
218
218
  });
219
219
 
220
220
  it('normalize', () => {
@@ -18,7 +18,8 @@ interface Options extends ParserOptions {
18
18
  }
19
19
 
20
20
  export function parse(source: string, opts: Options = {}, context?: MarkdownParser.Context): DocumentFragment {
21
- if (!validate(source, MAX_SEGMENT_SIZE)) throw new Error(`Too large input over ${MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.`);
21
+ if (!validate(source, MAX_SEGMENT_SIZE)) throw new Error(`Too large input over ${MAX_SEGMENT_SIZE.toLocaleString('en')} bytes`);
22
+ if (context?.id?.includes(':')) throw new Error('ID must not contain ":"');
22
23
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
23
24
  source = !context ? normalize(source) : source;
24
25
  assert(!context?.delimiters);
@@ -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([