securemark 0.281.1 → 0.281.3

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.281.3
4
+
5
+ - Refactoring.
6
+
7
+ ## 0.281.2
8
+
9
+ - Fix identifiers.
10
+
3
11
  ## 0.281.1
4
12
 
5
13
  - Fix identifiers.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.281.1 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.281.3 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"));
@@ -3169,6 +3169,7 @@ function context(base, parser) {
3169
3169
  }
3170
3170
  exports.context = context;
3171
3171
  function apply(parser, source, context, changes, values, reset = false) {
3172
+ reset && context.memo?.clear();
3172
3173
  for (let i = 0; i < changes.length; ++i) {
3173
3174
  const change = changes[i];
3174
3175
  const prop = change[0];
@@ -3190,9 +3191,6 @@ function apply(parser, source, context, changes, values, reset = false) {
3190
3191
  switch (prop) {
3191
3192
  case 'resources':
3192
3193
  break;
3193
- case 'memo':
3194
- context.memo.clear();
3195
- break;
3196
3194
  }
3197
3195
  context[prop] = values[i];
3198
3196
  values[i] = undefined;
@@ -3441,7 +3439,7 @@ Delimiters.matcher = (0, memoize_1.memoize)(pattern => {
3441
3439
  /***/ }),
3442
3440
 
3443
3441
  /***/ 1074:
3444
- /***/ ((__unused_webpack_module, exports) => {
3442
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
3445
3443
 
3446
3444
  "use strict";
3447
3445
 
@@ -3450,15 +3448,17 @@ Object.defineProperty(exports, "__esModule", ({
3450
3448
  value: true
3451
3449
  }));
3452
3450
  exports.Memo = void 0;
3451
+ const alias_1 = __webpack_require__(5413);
3453
3452
  class Memo {
3454
3453
  constructor(targets = ~0, margin = 0) {
3455
3454
  this.targets = targets;
3456
3455
  this.margin = margin;
3457
- this.memory = [];
3456
+ this.memory = {};
3458
3457
  this.count = 0;
3458
+ this.$length = 0;
3459
3459
  }
3460
3460
  get length() {
3461
- return this.memory.length;
3461
+ return this.$length;
3462
3462
  }
3463
3463
  get(position, syntax, state) {
3464
3464
  if (this.count === 0) return;
@@ -3467,21 +3467,23 @@ class Memo {
3467
3467
  return cache?.length === 2 ? [cache[0].slice(), cache[1]] : cache;
3468
3468
  }
3469
3469
  set(position, syntax, state, nodes, offset) {
3470
- this.count += +!this.memory[position - 1];
3471
- const record = this.memory[position - 1] ??= {};
3470
+ this.$length = (0, alias_1.max)(this.$length, position);
3471
+ const record = this.memory[position - 1] ??= (++this.count, {});
3472
3472
  (record[syntax] ??= {})[state] = nodes ? [nodes.slice(), offset] : [];
3473
3473
  //console.log('set', position, syntax, state, record[syntax]?.[state]);
3474
3474
  }
3475
3475
  resize(position) {
3476
3476
  const memory = this.memory;
3477
- for (let i = memory.length; i > position; --i) {
3478
- this.count -= +memory.pop();
3477
+ for (let i = this.$length; i > position; this.$length = --i) {
3478
+ if (!(i in memory)) continue;
3479
+ memory[i] &&= (--this.count, undefined);
3479
3480
  }
3480
3481
  //console.log('resize', position + 1);
3481
3482
  }
3482
3483
  clear() {
3483
- this.memory = [];
3484
+ this.memory = {};
3484
3485
  this.count = 0;
3486
+ this.$length = 0;
3485
3487
  }
3486
3488
  }
3487
3489
  exports.Memo = Memo;
@@ -3787,6 +3789,8 @@ Object.defineProperty(exports, "__esModule", ({
3787
3789
  }));
3788
3790
  exports.bind = void 0;
3789
3791
  const parser_1 = __webpack_require__(605);
3792
+ const memo_1 = __webpack_require__(1074);
3793
+ const context_1 = __webpack_require__(8669);
3790
3794
  const segment_1 = __webpack_require__(3967);
3791
3795
  const header_1 = __webpack_require__(3009);
3792
3796
  const block_1 = __webpack_require__(7099);
@@ -3799,7 +3803,8 @@ const array_1 = __webpack_require__(6876);
3799
3803
  function bind(target, settings) {
3800
3804
  let context = {
3801
3805
  ...settings,
3802
- host: settings.host ?? new url_1.ReadonlyURL(location.pathname, location.origin)
3806
+ host: settings.host ?? new url_1.ReadonlyURL(location.pathname, location.origin),
3807
+ memo: new memo_1.Memo(508 /* Syntax.targets */, context_1.Margin)
3803
3808
  };
3804
3809
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
3805
3810
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
@@ -4124,6 +4129,8 @@ Object.defineProperty(exports, "__esModule", ({
4124
4129
  }));
4125
4130
  exports.parse = void 0;
4126
4131
  const parser_1 = __webpack_require__(605);
4132
+ const memo_1 = __webpack_require__(1074);
4133
+ const context_1 = __webpack_require__(8669);
4127
4134
  const segment_1 = __webpack_require__(3967);
4128
4135
  const header_1 = __webpack_require__(3009);
4129
4136
  const block_1 = __webpack_require__(7099);
@@ -4142,7 +4149,8 @@ function parse(source, opts = {}, context) {
4142
4149
  url: url ? new url_1.ReadonlyURL(url) : context?.url,
4143
4150
  id: opts.id ?? context?.id,
4144
4151
  caches: context?.caches,
4145
- resources: context?.resources
4152
+ resources: context?.resources,
4153
+ memo: new memo_1.Memo(508 /* Syntax.targets */, context_1.Margin)
4146
4154
  };
4147
4155
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4148
4156
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
@@ -4196,7 +4204,6 @@ Object.defineProperty(exports, "__esModule", ({
4196
4204
  }));
4197
4205
  exports.block = void 0;
4198
4206
  const combinator_1 = __webpack_require__(3484);
4199
- const memo_1 = __webpack_require__(1074);
4200
4207
  const source_1 = __webpack_require__(8745);
4201
4208
  const pagebreak_1 = __webpack_require__(2946);
4202
4209
  const heading_1 = __webpack_require__(2778);
@@ -4219,8 +4226,7 @@ exports.block = (0, combinator_1.creation)(0, false, (0, combinator_1.reset)({
4219
4226
  resources: {
4220
4227
  clock: 20000,
4221
4228
  recursion: 20 + 1
4222
- },
4223
- memo: new memo_1.Memo(508 /* Syntax.targets */, 2)
4229
+ }
4224
4230
  }, error((0, combinator_1.union)([source_1.emptyline, pagebreak_1.pagebreak, heading_1.heading, ulist_1.ulist, olist_1.olist, ilist_1.ilist, dlist_1.dlist, table_1.table, codeblock_1.codeblock, mathblock_1.mathblock, extension_1.extension, sidefence_1.sidefence, blockquote_1.blockquote, mediablock_1.mediablock, reply_1.reply, paragraph_1.paragraph]))));
4225
4231
  function error(parser) {
4226
4232
  return (0, combinator_1.recover)((0, combinator_1.fallback)((0, combinator_1.open)('\x07', ({
@@ -4437,7 +4443,7 @@ exports.aside = (0, combinator_1.block)((0, combinator_1.validate)('~~~', (0, co
4437
4443
  'data-invalid-message': 'Missing the title at the first line'
4438
4444
  }, `${opener}${body}${closer}`)];
4439
4445
  return [(0, dom_1.html)('aside', {
4440
- id: (0, indexee_1.identity)(context.id, (0, indexee_1.index)(heading)),
4446
+ id: (0, indexee_1.identity)('index', context.id, heading),
4441
4447
  class: 'aside'
4442
4448
  }, [document, (0, dom_1.html)('h2', 'References'), references])];
4443
4449
  })));
@@ -5199,7 +5205,7 @@ exports.olist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combina
5199
5205
  exports.olist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.match)(openers['.'], (0, memoize_1.memoize)(ms => list(type(ms[1]), '.'), ms => idx(ms[1]), [])), (0, combinator_1.match)(openers['('], (0, memoize_1.memoize)(ms => list(type(ms[1]), '('), ms => idx(ms[1]), []))])));
5200
5206
  const list = (type, form) => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(heads[form], (0, combinator_1.subsequence)([ulist_1.checkbox, (0, combinator_1.trim)((0, visibility_1.visualize)((0, util_1.lineable)((0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline]))))))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([ulist_1.ulist_, exports.olist_, ilist_1.ilist_]))]), ulist_1.invalid), ns => [(0, dom_1.html)('li', {
5201
5207
  'data-marker': ns.shift() || undefined
5202
- }, (0, dom_1.defrag)((0, ulist_1.fillFirstLine)(ns)))]), true)]))), es => [format((0, dom_1.html)('ol', es), type, form)]);
5208
+ }, (0, dom_1.defrag)((0, ulist_1.fillFirstLine)(ns)))]))]))), es => [format((0, dom_1.html)('ol', es), type, form)]);
5203
5209
  const heads = {
5204
5210
  '.': (0, combinator_1.focus)(openers['.'], ({
5205
5211
  source
@@ -5523,7 +5529,7 @@ const visibility_1 = __webpack_require__(6364);
5523
5529
  const array_1 = __webpack_require__(6876);
5524
5530
  const dom_1 = __webpack_require__(394);
5525
5531
  exports.ulist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.validate)(/^-(?=[^\S\n]|\n[^\S\n]*\S)/, exports.ulist_)));
5526
- exports.ulist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)(/^-(?=$|\s)/, (0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(/^-(?:$|\s)/, (0, combinator_1.subsequence)([exports.checkbox, (0, combinator_1.trim)((0, visibility_1.visualize)((0, util_1.lineable)((0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline]))))))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([exports.ulist_, olist_1.olist_, ilist_1.ilist_]))]), exports.invalid), ns => [(0, dom_1.html)('li', (0, dom_1.defrag)(fillFirstLine(ns)))]), true)])))), es => [format((0, dom_1.html)('ul', es))])));
5532
+ exports.ulist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)(/^-(?=$|\s)/, (0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(/^-(?:$|\s)/, (0, combinator_1.subsequence)([exports.checkbox, (0, combinator_1.trim)((0, visibility_1.visualize)((0, util_1.lineable)((0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline]))))))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([exports.ulist_, olist_1.olist_, ilist_1.ilist_]))]), exports.invalid), ns => [(0, dom_1.html)('li', (0, dom_1.defrag)(fillFirstLine(ns)))]))])))), es => [format((0, dom_1.html)('ul', es))])));
5527
5533
  exports.checkbox = (0, combinator_1.creation)(1, false, (0, combinator_1.focus)(/^\[[xX ]\](?=$|\s)/, ({
5528
5534
  source
5529
5535
  }) => [[(0, dom_1.html)('span', {
@@ -5552,6 +5558,20 @@ function format(list) {
5552
5558
 
5553
5559
  /***/ }),
5554
5560
 
5561
+ /***/ 8669:
5562
+ /***/ ((__unused_webpack_module, exports) => {
5563
+
5564
+ "use strict";
5565
+
5566
+
5567
+ Object.defineProperty(exports, "__esModule", ({
5568
+ value: true
5569
+ }));
5570
+ exports.Margin = void 0;
5571
+ exports.Margin = 2;
5572
+
5573
+ /***/ }),
5574
+
5555
5575
  /***/ 3009:
5556
5576
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5557
5577
 
@@ -6057,7 +6077,7 @@ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0
6057
6077
  })]))));
6058
6078
  exports.signature = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('|', (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', {
6059
6079
  class: 'indexer',
6060
- 'data-index': (0, indexee_1.identity)(undefined, ns.join('')).slice(7)
6080
+ 'data-index': (0, indexee_1.identity)('index', undefined, ns.join('')).slice(7)
6061
6081
  })]))));
6062
6082
  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)(3, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true)])));
6063
6083
 
@@ -6072,15 +6092,15 @@ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, comb
6072
6092
  Object.defineProperty(exports, "__esModule", ({
6073
6093
  value: true
6074
6094
  }));
6075
- exports.text = exports.signature = exports.index = exports.identity = exports.indexee = void 0;
6095
+ exports.text = exports.signature = exports.identity = exports.indexee = void 0;
6076
6096
  const combinator_1 = __webpack_require__(3484);
6077
6097
  const memoize_1 = __webpack_require__(6925);
6078
6098
  const dom_1 = __webpack_require__(394);
6079
- function indexee(parser, optional) {
6099
+ function indexee(parser) {
6080
6100
  return (0, combinator_1.fmap)(parser, ([el], _, {
6081
6101
  id
6082
6102
  }) => [(0, dom_1.define)(el, {
6083
- id: identity(id, index(el, optional))
6103
+ id: identity('index', id, el)
6084
6104
  })]);
6085
6105
  }
6086
6106
  exports.indexee = indexee;
@@ -6088,20 +6108,23 @@ const MAX = 60;
6088
6108
  const ELLIPSIS = '...';
6089
6109
  const PART = (MAX - ELLIPSIS.length) / 2 | 0;
6090
6110
  const REM = MAX - PART * 2 - ELLIPSIS.length;
6091
- function identity(id, text, type = 'index') {
6111
+ function identity(type, id, text) {
6092
6112
  if (id === '') return undefined;
6113
+ if (typeof text !== 'string') {
6114
+ const index = text.querySelector(':scope > .indexer')?.getAttribute('data-index');
6115
+ if (index === '' && text.tagName === 'LI') return undefined;
6116
+ return index ? `${type}:${id ?? ''}:${index}` : identity(type, id, signature(text));
6117
+ }
6093
6118
  text = text.trim();
6094
6119
  if (text === '') return undefined;
6095
6120
  const str = text.replace(/\s/g, '_');
6096
6121
  const cs = [...str];
6097
- if (cs.length <= MAX || type === '') return `${type}:${id ?? ''}:${str}`;
6098
- switch (type) {
6099
- case 'index':
6100
- case 'mark':
6101
- const s1 = cs.slice(0, PART + REM).join('');
6102
- const s2 = cs.slice(-PART).join('');
6103
- return `${type}:${id ?? ''}:${s1}${ELLIPSIS}${s2}=${hash(text).toString(36)}`;
6122
+ if (type === '' || cs.length <= MAX) {
6123
+ return `${type}:${id ?? ''}:${str}${/_|[^\S ]/.test(text) ? `=${hash(text)}` : ''}`;
6104
6124
  }
6125
+ const s1 = cs.slice(0, PART + REM).join('');
6126
+ const s2 = cs.slice(-PART).join('');
6127
+ return `${type}:${id ?? ''}:${s1}${ELLIPSIS}${s2}=${hash(text)}`;
6105
6128
  }
6106
6129
  exports.identity = identity;
6107
6130
  function hash(source) {
@@ -6112,17 +6135,8 @@ function hash(source) {
6112
6135
  x ^= x >>> 17;
6113
6136
  x ^= x << 15;
6114
6137
  }
6115
- return x >>> 0;
6116
- }
6117
- function index(source, optional = false) {
6118
- if (!source.firstChild) return '';
6119
- const indexer = source.querySelector(':scope > .indexer');
6120
- const text = indexer?.getAttribute('data-index');
6121
- if (text === '' && optional) return '';
6122
- if (text) return [...text].length <= MAX ? text : text.replace(/=\w{1,7}$/, '');
6123
- return signature(source);
6138
+ return (x >>> 0).toString(36);
6124
6139
  }
6125
- exports.index = index;
6126
6140
  function signature(source) {
6127
6141
  const target = source.cloneNode(true);
6128
6142
  for (let es = target.querySelectorAll('code[data-src], .math[data-src], .label[data-label], .remark, rt, rp, br, .annotation, .reference, .checkbox, ul, ol'), len = es.length, i = 0; i < len; ++i) {
@@ -6539,7 +6553,7 @@ exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combi
6539
6553
  }) => {
6540
6554
  const el = (0, dom_1.html)('mark', (0, dom_1.defrag)(bs));
6541
6555
  return [[(0, dom_1.define)(el, {
6542
- id: (0, indexee_1.identity)(id, (0, indexee_1.signature)(el), 'mark')
6556
+ id: (0, indexee_1.identity)('mark', id, (0, indexee_1.signature)(el))
6543
6557
  }), el.id && (0, dom_1.html)('a', {
6544
6558
  href: `#${el.id}`
6545
6559
  })], rest];
@@ -7054,7 +7068,7 @@ function build(syntax, marker, splitter = '') {
7054
7068
  const content = ref.firstElementChild;
7055
7069
  content.replaceWith(content.cloneNode());
7056
7070
  const abbr = ref.getAttribute('data-abbr') ?? '';
7057
- const identifier = abbr ? (0, indexee_1.identity)(undefined, abbr.match(/^(?:\S+ )+?(?:(?:January|February|March|April|May|June|August|September|October|November|December) \d{1,2}(?:-\d{0,2})?, \d{1,4}(?:-\d{0,4})?[a-z]?|n\.d\.)(?=,|$)/)?.[0] ?? abbr.match(/^[^,\s]+(?:,? [^,\s]+)*?(?: \d{1,4}(?:-\d{0,4})?[a-z]?(?=,|$)|(?=,(?: [a-z]+\.?)? [0-9]))/)?.[0] ?? abbr, '')?.slice(2) || '' : (0, indexee_1.identity)(undefined, (0, indexee_1.signature)(content), 'mark')?.slice(6) || '';
7071
+ const identifier = abbr ? (0, indexee_1.identity)('', undefined, abbr.match(/^(?:\S+ )+?(?:(?:January|February|March|April|May|June|August|September|October|November|December) \d{1,2}(?:-\d{0,2})?, \d{1,4}(?:-\d{0,4})?[a-z]?|n\.d\.)(?=,|$)/)?.[0] ?? abbr.match(/^[^,\s]+(?:,? [^,\s]+)*?(?: \d{1,4}(?:-\d{0,4})?[a-z]?(?=,|$)|(?=,(?: [a-z]+\.?)? [0-9]))/)?.[0] ?? abbr)?.slice(2) || '' : (0, indexee_1.identity)('mark', undefined, (0, indexee_1.signature)(content))?.slice(6) || '';
7058
7072
  return {
7059
7073
  content,
7060
7074
  identifier,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.281.1",
3
+ "version": "0.281.3",
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",
@@ -1,19 +1,22 @@
1
+ import { max } from 'spica/alias';
2
+
1
3
  export class Memo {
2
4
  constructor(
3
5
  public readonly targets = ~0,
4
6
  public readonly margin = 0,
5
7
  ) {
6
8
  }
7
- private memory: Record<number, Record<number, readonly [any[], number] | readonly []>>[/* pos */] = [];
9
+ private memory: Record<number, Record<number, Record<number, readonly [unknown[], number] | readonly []>> | undefined> = {};
8
10
  private count = 0;
11
+ private $length = 0;
9
12
  public get length(): number {
10
- return this.memory.length;
13
+ return this.$length;
11
14
  }
12
15
  public get(
13
16
  position: number,
14
17
  syntax: number,
15
18
  state: number,
16
- ): readonly [any[], number] | readonly [] | undefined {
19
+ ): readonly [unknown[], number] | readonly [] | undefined {
17
20
  assert(position > 0);
18
21
  if (this.count === 0) return;
19
22
  //console.log('get', position, syntax, state, this.memory[position - 1]?.[syntax]?.[state]);
@@ -26,12 +29,12 @@ export class Memo {
26
29
  position: number,
27
30
  syntax: number,
28
31
  state: number,
29
- nodes: any[] | undefined,
32
+ nodes: unknown[] | undefined,
30
33
  offset: number,
31
34
  ): void {
32
35
  assert(position > 0);
33
- this.count += +!this.memory[position - 1];
34
- const record = this.memory[position - 1] ??= {};
36
+ this.$length = max(this.$length, position);
37
+ const record = this.memory[position - 1] ??= (++this.count, {});
35
38
  assert(!record[syntax]?.[state]);
36
39
  (record[syntax] ??= {})[state] = nodes
37
40
  ? [nodes.slice(), offset]
@@ -40,13 +43,15 @@ export class Memo {
40
43
  }
41
44
  public resize(position: number): void {
42
45
  const memory = this.memory;
43
- for (let i = memory.length; i > position; --i) {
44
- this.count -= +memory.pop()!;
46
+ for (let i = this.$length; i > position; this.$length = --i) {
47
+ if (!(i in memory)) continue;
48
+ memory[i] &&= (--this.count, undefined);
45
49
  }
46
50
  //console.log('resize', position + 1);
47
51
  }
48
52
  public clear(): void {
49
- this.memory = [];
53
+ this.memory = {};
50
54
  this.count = 0;
55
+ this.$length = 0;
51
56
  }
52
57
  }
@@ -24,6 +24,7 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
24
24
 
25
25
  function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Tree<P>>;
26
26
  function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<T> {
27
+ reset && context.memo?.clear();
27
28
  for (let i = 0; i < changes.length; ++i) {
28
29
  const change = changes[i];
29
30
  const prop = change[0];
@@ -34,7 +35,6 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
34
35
  assert(!context.precedence);
35
36
  assert(!context.delimiters);
36
37
  assert(!context.state);
37
- assert(!context.memo);
38
38
  context[prop as string] ??= ObjectCreate(change[1] as object);
39
39
  continue;
40
40
  }
@@ -49,10 +49,6 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
49
49
  case 'resources':
50
50
  assert(reset);
51
51
  break;
52
- case 'memo':
53
- assert(reset);
54
- context.memo!.clear();
55
- break;
56
52
  }
57
53
  context[prop] = values[i];
58
54
  values[i] = undefined;
@@ -61,7 +57,7 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
61
57
  }
62
58
 
63
59
  export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number, state: number, parser: P): P;
64
- export function syntax<T>(syntax: number, prec: number, state: number, parser?: Parser<T>): Parser<T> {
60
+ export function syntax<T>(syntax: number, prec: number, state: number, parser: Parser<T>): Parser<T> {
65
61
  return precedence(prec, ({ source, context }) => {
66
62
  if (source === '') return;
67
63
  const memo = context.memo ??= new Memo();
@@ -73,12 +69,12 @@ export function syntax<T>(syntax: number, prec: number, state: number, parser?:
73
69
  const result: Result<T> = cache
74
70
  ? cache.length === 0
75
71
  ? undefined
76
- : [cache[0], source.slice(cache[1])]
77
- : parser!({ source, context });
72
+ : [cache[0] as T[], source.slice(cache[1])]
73
+ : parser({ source, context });
78
74
  if (stateOuter && !cache && syntax & memo.targets) {
79
75
  memo.set(position, syntax, stateInner, eval(result), source.length - exec(result, '').length);
80
76
  }
81
- else if (!stateOuter && result && memo.length! >= position + memo.margin) {
77
+ else if (!stateOuter && result && memo.length >= position + memo.margin) {
82
78
  memo.resize(position + memo.margin);
83
79
  }
84
80
  context.state = stateOuter;
@@ -1,6 +1,8 @@
1
1
  import { ParserSettings, Progress } from '../../..';
2
2
  import { MarkdownParser } from '../../../markdown';
3
3
  import { eval } from '../../combinator/data/parser';
4
+ import { Memo } from '../../combinator/data/parser/context/memo';
5
+ import { Syntax, Margin } from '../context';
4
6
  import { segment, validate, MAX_INPUT_SIZE } from '../segment';
5
7
  import { header } from '../header';
6
8
  import { block } from '../block';
@@ -22,12 +24,12 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
22
24
  let context: MarkdownParser.Context = {
23
25
  ...settings,
24
26
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
27
+ memo: new Memo(Syntax.targets, Margin),
25
28
  };
26
29
  assert(!context.offset);
27
30
  assert(!context.precedence);
28
31
  assert(!context.delimiters);
29
32
  assert(!context.state);
30
- assert(!context.memo);
31
33
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
32
34
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
33
35
  type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
@@ -1,6 +1,8 @@
1
1
  import { ParserOptions } from '../../..';
2
2
  import { MarkdownParser } from '../../../markdown';
3
3
  import { eval } from '../../combinator/data/parser';
4
+ import { Memo } from '../../combinator/data/parser/context/memo';
5
+ import { Syntax, Margin } from '../context';
4
6
  import { segment, validate, MAX_SEGMENT_SIZE } from '../segment';
5
7
  import { header } from '../header';
6
8
  import { block } from '../block';
@@ -25,12 +27,12 @@ export function parse(source: string, opts: Options = {}, context?: MarkdownPars
25
27
  id: opts.id ?? context?.id,
26
28
  caches: context?.caches,
27
29
  resources: context?.resources,
30
+ memo: new Memo(Syntax.targets, Margin),
28
31
  };
29
32
  assert(!context.offset);
30
33
  assert(!context.precedence);
31
34
  assert(!context.delimiters);
32
35
  assert(!context.state);
33
- assert(!context.memo);
34
36
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
35
37
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
36
38
  const node = frag();
@@ -1,6 +1,6 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { block, validate, fence, fmap } from '../../../combinator';
3
- import { identity, index } from '../../inline/extension/indexee';
3
+ import { identity } from '../../inline/extension/indexee';
4
4
  import { parse } from '../../api/parse';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
@@ -34,9 +34,9 @@ export const aside: ExtensionParser.AsideParser = block(validate('~~~', fmap(
34
34
  'data-invalid-type': 'content',
35
35
  'data-invalid-message': 'Missing the title at the first line',
36
36
  }, `${opener}${body}${closer}`)];
37
- assert(identity(context.id, index(heading)));
37
+ assert(identity('index', context.id, heading));
38
38
  return [
39
- html('aside', { id: identity(context.id, index(heading)), class: 'aside' }, [
39
+ html('aside', { id: identity('index', context.id, heading), class: 'aside' }, [
40
40
  document,
41
41
  html('h2', 'References'),
42
42
  references,
@@ -39,7 +39,7 @@ const list = (type: string, form: string): OListParser.ListParser => fmap(
39
39
  indent(union([ulist_, olist_, ilist_])),
40
40
  ]),
41
41
  invalid),
42
- ns => [html('li', { 'data-marker': ns.shift() as string || undefined }, defrag(fillFirstLine(ns)))]), true),
42
+ ns => [html('li', { 'data-marker': ns.shift() as string || undefined }, defrag(fillFirstLine(ns)))])),
43
43
  ]))),
44
44
  es => [format(html('ol', es), type, form)]);
45
45
 
@@ -26,7 +26,7 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
26
26
  indent(union([ulist_, olist_, ilist_])),
27
27
  ]),
28
28
  invalid),
29
- ns => [html('li', defrag(fillFirstLine(ns)))]), true),
29
+ ns => [html('li', defrag(fillFirstLine(ns)))])),
30
30
  ])))),
31
31
  es => [format(html('ul', es))])));
32
32
 
@@ -1,6 +1,5 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
2
  import { union, reset, creation, open, fallback, recover } from '../combinator';
3
- import { Memo } from '../combinator/data/parser/context/memo';
4
3
  import { emptyline } from './source';
5
4
  import { pagebreak } from './block/pagebreak';
6
5
  import { heading } from './block/heading';
@@ -17,7 +16,6 @@ import { blockquote } from './block/blockquote';
17
16
  import { mediablock } from './block/mediablock';
18
17
  import { reply } from './block/reply';
19
18
  import { paragraph } from './block/paragraph';
20
- import { Syntax } from './context';
21
19
  import { rnd0Z } from 'spica/random';
22
20
  import { html } from 'typed-dom/dom';
23
21
 
@@ -41,7 +39,6 @@ export import ParagraphParser = BlockParser.ParagraphParser;
41
39
  export const block: BlockParser = creation(0, false,
42
40
  reset({
43
41
  resources: { clock: 20000, recursion: 20 + 1 },
44
- memo: new Memo(Syntax.targets, 2),
45
42
  },
46
43
  error(union([
47
44
  emptyline,
@@ -39,3 +39,5 @@ export const enum State {
39
39
  | State.mark
40
40
  | State.autolink,
41
41
  }
42
+
43
+ export const Margin = 2;
@@ -44,13 +44,15 @@ describe('Unit: parser/inline/extension/index', () => {
44
44
  assert.deepStrictEqual(inspect(parser('[#a]')), [['<a class="index" href="#index::a">a</a>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser('[#a ]')), [['<a class="index" href="#index::a">a</a>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser('[#a ]')), [['<a class="index" href="#index::a">a</a>'], '']);
47
- assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
48
- assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a__b">a b</a>'], '']);
49
47
  assert.deepStrictEqual(inspect(parser('[#a \\ ]')), [['<a class="index" href="#index::a">a</a>'], '']);
50
48
  assert.deepStrictEqual(inspect(parser('[#a &nbsp;]')), [['<a class="index" href="#index::a">a</a>'], '']);
51
49
  assert.deepStrictEqual(inspect(parser('[#a <wbr>]')), [['<a class="index" href="#index::a">a</a>'], '']);
52
50
  assert.deepStrictEqual(inspect(parser('[#a [% b %]]')), [['<a class="index" href="#index::a">a <span class="remark"><input type="checkbox"><span>[% b %]</span></span></a>'], '']);
53
51
  assert.deepStrictEqual(inspect(parser('[#a\\ ]')), [['<a class="index" href="#index::a">a</a>'], '']);
52
+ assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('[#a b]')), [['<a class="index" href="#index::a__b">a b</a>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('[#a\tb]')), [['<a class="index" href="#index::a_b=1eu1tj4">a\tb</a>'], '']);
55
+ assert.deepStrictEqual(inspect(parser('[#a_b]')), [['<a class="index" href="#index::a_b=10dxc9b">a_b</a>'], '']);
54
56
  assert.deepStrictEqual(inspect(parser('[#a\\ b]')), [['<a class="index" href="#index::a_b">a b</a>'], '']);
55
57
  assert.deepStrictEqual(inspect(parser('[#[]]')), [['<a class="index" href="#index::[]">[]</a>'], '']);
56
58
  assert.deepStrictEqual(inspect(parser('[#\\]]')), [['<a class="index" href="#index::]">]</a>'], '']);
@@ -85,6 +87,8 @@ describe('Unit: parser/inline/extension/index', () => {
85
87
  assert.deepStrictEqual(inspect(parser('[#a|*b*]')), [['<a class="index" href="#index::*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
86
88
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
87
89
  assert.deepStrictEqual(inspect(parser('[#a|b c]')), [['<a class="index" href="#index::b__c">a<span class="indexer" data-index="b__c"></span></a>'], '']);
90
+ assert.deepStrictEqual(inspect(parser('[#a|b\tc]')), [['<a class="index" href="#index::b_c=3p5wqt">a<span class="indexer" data-index="b_c=3p5wqt"></span></a>'], '']);
91
+ assert.deepStrictEqual(inspect(parser('[#a|b_c]')), [['<a class="index" href="#index::b_c=fvw9e2">a<span class="indexer" data-index="b_c=fvw9e2"></span></a>'], '']);
88
92
  assert.deepStrictEqual(inspect(parser('[#a|[]]')), [['<a class="index" href="#index::[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
89
93
  assert.deepStrictEqual(inspect(parser('[#a|&copy;]')), [['<a class="index" href="#index::&amp;copy;">a<span class="indexer" data-index="&amp;copy;"></span></a>'], '']);
90
94
  assert.deepStrictEqual(inspect(parser('[#a |b]')), [['<a class="index" href="#index::b">a<span class="indexer" data-index="b"></span></a>'], '']);
@@ -34,7 +34,7 @@ export const signature: IndexParser.SignatureParser = lazy(() => validate('|', c
34
34
  '|',
35
35
  startTight(some(union([bracket, txt]), ']'))),
36
36
  ns => [
37
- html('span', { class: 'indexer', 'data-index': identity(undefined, ns.join(''))!.slice(7) }),
37
+ html('span', { class: 'indexer', 'data-index': identity('index', undefined, ns.join(''))!.slice(7) }),
38
38
  ]))));
39
39
 
40
40
  const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(union([
@@ -4,9 +4,9 @@ import { fmap } from '../../../combinator';
4
4
  import { reduce } from 'spica/memoize';
5
5
  import { define } from 'typed-dom/dom';
6
6
 
7
- export function indexee<P extends Parser<unknown, MarkdownParser.Context>>(parser: P, optional?: boolean): P;
8
- export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>, optional?: boolean): Parser<HTMLElement> {
9
- return fmap(parser, ([el], _, { id }) => [define(el, { id: identity(id, index(el, optional)) })]);
7
+ export function indexee<P extends Parser<unknown, MarkdownParser.Context>>(parser: P): P;
8
+ export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>): Parser<HTMLElement> {
9
+ return fmap(parser, ([el], _, { id }) => [define(el, { id: identity('index', id, el) })]);
10
10
  }
11
11
 
12
12
  const MAX = 60;
@@ -14,44 +14,50 @@ const ELLIPSIS = '...';
14
14
  const PART = (MAX - ELLIPSIS.length) / 2 | 0;
15
15
  const REM = MAX - PART * 2 - ELLIPSIS.length;
16
16
  export function identity(
17
+ type: 'index' | 'mark' | '',
17
18
  id: string | undefined,
18
- text: string,
19
- type: 'index' | 'mark' | '' = 'index',
19
+ text: string | HTMLElement,
20
20
  ): string | undefined {
21
21
  assert(id?.match(/^[0-9a-z/-]*$/i) ?? true);
22
- assert(!text.includes('\n'));
23
22
  if (id === '') return undefined;
23
+ if (typeof text !== 'string') {
24
+ const index = text.querySelector(':scope > .indexer')?.getAttribute('data-index');
25
+ if (index === '' && text.tagName === 'LI') return undefined;
26
+ return index
27
+ ? `${type}:${id ?? ''}:${index}`
28
+ : identity(type, id, signature(text));
29
+ }
24
30
  text = text.trim();
25
31
  if (text === '') return undefined;
26
32
  const str = text.replace(/\s/g, '_');
27
33
  const cs = [...str];
28
- if (cs.length <= MAX || type === '') return `${type}:${id ?? ''}:${str}`;
29
- switch (type) {
30
- case 'index':
31
- case 'mark':
32
- const s1 = cs.slice(0, PART + REM).join('');
33
- const s2 = cs.slice(-PART).join('');
34
- assert([...`${s1}${ELLIPSIS}${s2}`].length === MAX);
35
- return `${type}:${id ?? ''}:${s1}${ELLIPSIS}${s2}=${hash(text).toString(36)}`;
34
+ if (type === '' || cs.length <= MAX) {
35
+ return `${type}:${id ?? ''}:${str}${/_|[^\S ]/.test(text) ? `=${hash(text)}` : ''}`;
36
36
  }
37
- assert(false);
37
+ const s1 = cs.slice(0, PART + REM).join('');
38
+ const s2 = cs.slice(-PART).join('');
39
+ assert([...`${s1}${ELLIPSIS}${s2}`].length === MAX);
40
+ return `${type}:${id ?? ''}:${s1}${ELLIPSIS}${s2}=${hash(text)}`;
38
41
  }
39
42
  assert.deepStrictEqual(
40
- identity(undefined, `${'0'.repeat(MAX - 1)}1`)!.slice(7),
43
+ identity('index', undefined, ' 0 '),
44
+ identity('index', undefined, ' 0 '.trim()));
45
+ assert.notDeepStrictEqual(
46
+ identity('index', undefined, '0 0'),
47
+ identity('index', undefined, '0_0'));
48
+ assert.notDeepStrictEqual(
49
+ identity('index', undefined, '0 0'),
50
+ identity('index', undefined, '0\t0'));
51
+ assert.deepStrictEqual(
52
+ identity('index', undefined, `${'0'.repeat(MAX - 1)}1`)!.slice(7),
41
53
  `${'0'.repeat(MAX - 1)}1`);
42
54
  assert.deepStrictEqual(
43
- identity(undefined, `0${'1'.repeat(MAX / 2)}${'2'.repeat(MAX / 2)}3`)!.slice(7),
55
+ identity('index', undefined, `0${'1'.repeat(MAX / 2)}${'2'.repeat(MAX / 2)}3`)!.slice(7),
44
56
  `0${'1'.repeat(PART + REM - 1)}${ELLIPSIS}${'2'.repeat(PART - 1)}3=mhy513`);
45
57
  assert.deepStrictEqual(
46
- identity(undefined, `0${'1'.repeat(MAX * 2)}${'2'.repeat(MAX * 2)}3`)!.slice(7),
58
+ identity('index', undefined, `0${'1'.repeat(MAX * 2)}${'2'.repeat(MAX * 2)}3`)!.slice(7),
47
59
  `0${'1'.repeat(PART + REM - 1)}${ELLIPSIS}${'2'.repeat(PART - 1)}3=12jqtiv`);
48
- assert.deepStrictEqual(
49
- identity(undefined, ` ${'0 '.repeat(MAX)}`)!.slice(7),
50
- identity(undefined, ` ${'0 '.repeat(MAX)}`.trim())!.slice(7));
51
- assert.notDeepStrictEqual(
52
- identity(undefined, `${'0 '.repeat(MAX)}`)!.slice(7),
53
- identity(undefined, `${'0_'.repeat(MAX)}`)!.slice(7));
54
- function hash(source: string): number {
60
+ function hash(source: string): string {
55
61
  let x = 0;
56
62
  for (let i = 0; i < source.length; ++i) {
57
63
  x ^= source.charCodeAt(i) << 1 | 1; // 16+1bit
@@ -59,33 +65,12 @@ function hash(source: string): number {
59
65
  x ^= x >>> 17;
60
66
  x ^= x << 15;
61
67
  }
62
- return x >>> 0;
68
+ return (x >>> 0).toString(36);
63
69
  }
64
- assert(hash('\x00') !== 0);
65
- assert(hash('\x01') !== 0);
70
+ assert(hash('\x00') !== '0');
71
+ assert(hash('\x01') !== '0');
66
72
  assert(hash('\x00') !== hash(String.fromCharCode(1 << 15)));
67
73
 
68
- export function index(source: Element, optional = false): string {
69
- assert(!source.matches('.indexer'));
70
- assert(source.querySelectorAll(':scope > .indexer').length <= 1);
71
- if (!source.firstChild) return '';
72
- const indexer = source.querySelector(':scope > .indexer');
73
- const text = indexer?.getAttribute('data-index');
74
- if (text === '' && optional) return '';
75
- if (text) return [...text].length <= MAX ? text : text.replace(/=\w{1,7}$/, '');
76
- return signature(source);
77
- }
78
- assert.deepStrictEqual(
79
- index(define(document.createElement('b'), [
80
- define(document.createElement('b'), { class: 'indexer', 'data-index': '0'.repeat(MAX - 2) + '=0' })
81
- ])),
82
- '0'.repeat(MAX - 2) + '=0');
83
- assert.deepStrictEqual(
84
- index(define(document.createElement('b'), [
85
- define(document.createElement('b'), { class: 'indexer', 'data-index': '0'.repeat(MAX) + '=0' })
86
- ])),
87
- '0'.repeat(MAX));
88
-
89
74
  export function signature(source: Element | DocumentFragment): string {
90
75
  assert(!navigator.userAgent.includes('Chrome') || !source.querySelector('br:not(:has(+ :is(ul, ol)))'));
91
76
  const target = source.cloneNode(true) as typeof source;
@@ -25,6 +25,8 @@ describe('Unit: parser/inline/extension/indexer', () => {
25
25
  assert.deepStrictEqual(inspect(parser(' [|a ]')), [['<span class="indexer" data-index="a"></span>'], '']);
26
26
  assert.deepStrictEqual(inspect(parser(' [|a b]')), [['<span class="indexer" data-index="a_b"></span>'], '']);
27
27
  assert.deepStrictEqual(inspect(parser(' [|a b]')), [['<span class="indexer" data-index="a__b"></span>'], '']);
28
+ assert.deepStrictEqual(inspect(parser(' [|a\tb]')), [['<span class="indexer" data-index="a_b=1eu1tj4"></span>'], '']);
29
+ assert.deepStrictEqual(inspect(parser(' [|a_b]')), [['<span class="indexer" data-index="a_b=10dxc9b"></span>'], '']);
28
30
  assert.deepStrictEqual(inspect(parser(' [|A]')), [['<span class="indexer" data-index="A"></span>'], '']);
29
31
  assert.deepStrictEqual(inspect(parser(' [|*A*]')), [['<span class="indexer" data-index="*A*"></span>'], '']);
30
32
  assert.deepStrictEqual(inspect(parser(' [|`A`]')), [['<span class="indexer" data-index="`A`"></span>'], '']);
@@ -38,7 +38,7 @@ describe('Unit: parser/inline/mark', () => {
38
38
  it('nest', () => {
39
39
  assert.deepStrictEqual(inspect(parser('==a ==b====')), [['<mark id="mark::a_b">a <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
40
40
  assert.deepStrictEqual(inspect(parser('==a\\ ==b====')), [['<mark id="mark::a_b">a <mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
41
- assert.deepStrictEqual(inspect(parser('==a&Tab;==b====')), [['<mark id="mark::a_b">a\t<mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b"></a>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('==a&Tab;==b====')), [['<mark id="mark::a_b=1eu1tj4">a\t<mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::a_b=1eu1tj4"></a>'], '']);
42
42
  assert.deepStrictEqual(inspect(parser('==a<wbr>==b====')), [['<mark id="mark::ab">a<wbr><mark id="mark::b">b</mark><a href="#mark::b"></a></mark>', '<a href="#mark::ab"></a>'], '']);
43
43
  assert.deepStrictEqual(inspect(parser('==*==a==*==')), [['<mark id="mark::a"><em><mark id="mark::a">a</mark><a href="#mark::a"></a></em></mark>', '<a href="#mark::a"></a>'], '']);
44
44
  });
@@ -20,7 +20,7 @@ export const mark: MarkParser = lazy(() => creation(surround(
20
20
  ([, bs], rest, { id }) => {
21
21
  const el = html('mark', defrag(bs));
22
22
  return [[
23
- define(el, { id: identity(id, signature(el), 'mark') }),
23
+ define(el, { id: identity('mark', id, signature(el)) }),
24
24
  el.id && html('a', { href: `#${el.id}` }),
25
25
  ], rest];
26
26
  },
@@ -39,14 +39,14 @@ function build(
39
39
  const abbr = ref.getAttribute('data-abbr') ?? '';
40
40
  const identifier = abbr
41
41
  ? identity(
42
+ '',
42
43
  undefined,
43
44
  (
44
45
  abbr.match(/^(?:\S+ )+?(?:(?:January|February|March|April|May|June|August|September|October|November|December) \d{1,2}(?:-\d{0,2})?, \d{1,4}(?:-\d{0,4})?[a-z]?|n\.d\.)(?=,|$)/)?.[0] ??
45
46
  abbr.match(/^[^,\s]+(?:,? [^,\s]+)*?(?: \d{1,4}(?:-\d{0,4})?[a-z]?(?=,|$)|(?=,(?: [a-z]+\.?)? [0-9]))/)?.[0] ??
46
47
  abbr
47
- ),
48
- '')?.slice(2) || ''
49
- : identity(undefined, signature(content), 'mark')?.slice(6) || '';
48
+ ))?.slice(2) || ''
49
+ : identity('mark', undefined, signature(content))?.slice(6) || '';
50
50
  return {
51
51
  content,
52
52
  identifier,