securemark 0.281.1 → 0.281.2

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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.281.2
4
+
5
+ - Fix identifiers.
6
+
3
7
  ## 0.281.1
4
8
 
5
9
  - 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.2 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"));
@@ -4437,7 +4437,7 @@ exports.aside = (0, combinator_1.block)((0, combinator_1.validate)('~~~', (0, co
4437
4437
  'data-invalid-message': 'Missing the title at the first line'
4438
4438
  }, `${opener}${body}${closer}`)];
4439
4439
  return [(0, dom_1.html)('aside', {
4440
- id: (0, indexee_1.identity)(context.id, (0, indexee_1.index)(heading)),
4440
+ id: (0, indexee_1.identity)('index', context.id, heading),
4441
4441
  class: 'aside'
4442
4442
  }, [document, (0, dom_1.html)('h2', 'References'), references])];
4443
4443
  })));
@@ -5199,7 +5199,7 @@ exports.olist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combina
5199
5199
  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
5200
  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
5201
  '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)]);
5202
+ }, (0, dom_1.defrag)((0, ulist_1.fillFirstLine)(ns)))]))]))), es => [format((0, dom_1.html)('ol', es), type, form)]);
5203
5203
  const heads = {
5204
5204
  '.': (0, combinator_1.focus)(openers['.'], ({
5205
5205
  source
@@ -5523,7 +5523,7 @@ const visibility_1 = __webpack_require__(6364);
5523
5523
  const array_1 = __webpack_require__(6876);
5524
5524
  const dom_1 = __webpack_require__(394);
5525
5525
  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))])));
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)))]))])))), es => [format((0, dom_1.html)('ul', es))])));
5527
5527
  exports.checkbox = (0, combinator_1.creation)(1, false, (0, combinator_1.focus)(/^\[[xX ]\](?=$|\s)/, ({
5528
5528
  source
5529
5529
  }) => [[(0, dom_1.html)('span', {
@@ -6057,7 +6057,7 @@ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0
6057
6057
  })]))));
6058
6058
  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
6059
  class: 'indexer',
6060
- 'data-index': (0, indexee_1.identity)(undefined, ns.join('')).slice(7)
6060
+ 'data-index': (0, indexee_1.identity)('index', undefined, ns.join('')).slice(7)
6061
6061
  })]))));
6062
6062
  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
6063
 
@@ -6072,15 +6072,15 @@ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, comb
6072
6072
  Object.defineProperty(exports, "__esModule", ({
6073
6073
  value: true
6074
6074
  }));
6075
- exports.text = exports.signature = exports.index = exports.identity = exports.indexee = void 0;
6075
+ exports.text = exports.signature = exports.identity = exports.indexee = void 0;
6076
6076
  const combinator_1 = __webpack_require__(3484);
6077
6077
  const memoize_1 = __webpack_require__(6925);
6078
6078
  const dom_1 = __webpack_require__(394);
6079
- function indexee(parser, optional) {
6079
+ function indexee(parser) {
6080
6080
  return (0, combinator_1.fmap)(parser, ([el], _, {
6081
6081
  id
6082
6082
  }) => [(0, dom_1.define)(el, {
6083
- id: identity(id, index(el, optional))
6083
+ id: identity('index', id, el)
6084
6084
  })]);
6085
6085
  }
6086
6086
  exports.indexee = indexee;
@@ -6088,20 +6088,23 @@ const MAX = 60;
6088
6088
  const ELLIPSIS = '...';
6089
6089
  const PART = (MAX - ELLIPSIS.length) / 2 | 0;
6090
6090
  const REM = MAX - PART * 2 - ELLIPSIS.length;
6091
- function identity(id, text, type = 'index') {
6091
+ function identity(type, id, text) {
6092
6092
  if (id === '') return undefined;
6093
+ if (typeof text !== 'string') {
6094
+ const index = text.querySelector(':scope > .indexer')?.getAttribute('data-index');
6095
+ if (index === '' && text.tagName === 'LI') return undefined;
6096
+ return index ? `${type}:${id ?? ''}:${index}` : identity(type, id, signature(text));
6097
+ }
6093
6098
  text = text.trim();
6094
6099
  if (text === '') return undefined;
6095
6100
  const str = text.replace(/\s/g, '_');
6096
6101
  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)}`;
6102
+ if (type === '' || cs.length <= MAX) {
6103
+ return `${type}:${id ?? ''}:${str}${/_|[^\S ]/.test(text) ? `=${hash(text)}` : ''}`;
6104
6104
  }
6105
+ const s1 = cs.slice(0, PART + REM).join('');
6106
+ const s2 = cs.slice(-PART).join('');
6107
+ return `${type}:${id ?? ''}:${s1}${ELLIPSIS}${s2}=${hash(text)}`;
6105
6108
  }
6106
6109
  exports.identity = identity;
6107
6110
  function hash(source) {
@@ -6112,17 +6115,8 @@ function hash(source) {
6112
6115
  x ^= x >>> 17;
6113
6116
  x ^= x << 15;
6114
6117
  }
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);
6118
+ return (x >>> 0).toString(36);
6124
6119
  }
6125
- exports.index = index;
6126
6120
  function signature(source) {
6127
6121
  const target = source.cloneNode(true);
6128
6122
  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 +6533,7 @@ exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combi
6539
6533
  }) => {
6540
6534
  const el = (0, dom_1.html)('mark', (0, dom_1.defrag)(bs));
6541
6535
  return [[(0, dom_1.define)(el, {
6542
- id: (0, indexee_1.identity)(id, (0, indexee_1.signature)(el), 'mark')
6536
+ id: (0, indexee_1.identity)('mark', id, (0, indexee_1.signature)(el))
6543
6537
  }), el.id && (0, dom_1.html)('a', {
6544
6538
  href: `#${el.id}`
6545
6539
  })], rest];
@@ -7054,7 +7048,7 @@ function build(syntax, marker, splitter = '') {
7054
7048
  const content = ref.firstElementChild;
7055
7049
  content.replaceWith(content.cloneNode());
7056
7050
  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) || '';
7051
+ 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
7052
  return {
7059
7053
  content,
7060
7054
  identifier,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.281.1",
3
+ "version": "0.281.2",
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,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
 
@@ -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,