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 +8 -0
- package/dist/index.js +58 -44
- package/package.json +1 -1
- package/src/combinator/data/parser/context/memo.ts +14 -9
- package/src/combinator/data/parser/context.ts +5 -9
- package/src/parser/api/bind.ts +3 -1
- package/src/parser/api/parse.ts +3 -1
- package/src/parser/block/extension/aside.ts +3 -3
- package/src/parser/block/olist.ts +1 -1
- package/src/parser/block/ulist.ts +1 -1
- package/src/parser/block.ts +0 -3
- package/src/parser/context.ts +2 -0
- package/src/parser/inline/extension/index.test.ts +6 -2
- package/src/parser/inline/extension/index.ts +1 -1
- package/src/parser/inline/extension/indexee.ts +34 -49
- package/src/parser/inline/extension/indexer.test.ts +2 -0
- package/src/parser/inline/mark.test.ts +1 -1
- package/src/parser/inline/mark.ts +1 -1
- package/src/parser/processor/note.ts +3 -3
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.281.
|
|
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
|
|
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
|
|
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 =
|
|
3478
|
-
|
|
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,
|
|
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)))])
|
|
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)))])
|
|
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.
|
|
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
|
|
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,
|
|
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
|
|
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 (
|
|
6098
|
-
|
|
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)
|
|
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
|
|
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,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 [
|
|
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
|
|
13
|
+
return this.$length;
|
|
11
14
|
}
|
|
12
15
|
public get(
|
|
13
16
|
position: number,
|
|
14
17
|
syntax: number,
|
|
15
18
|
state: number,
|
|
16
|
-
): readonly [
|
|
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:
|
|
32
|
+
nodes: unknown[] | undefined,
|
|
30
33
|
offset: number,
|
|
31
34
|
): void {
|
|
32
35
|
assert(position > 0);
|
|
33
|
-
this
|
|
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 =
|
|
44
|
-
|
|
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
|
|
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
|
|
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
|
|
77
|
+
else if (!stateOuter && result && memo.length >= position + memo.margin) {
|
|
82
78
|
memo.resize(position + memo.margin);
|
|
83
79
|
}
|
|
84
80
|
context.state = stateOuter;
|
package/src/parser/api/bind.ts
CHANGED
|
@@ -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];
|
package/src/parser/api/parse.ts
CHANGED
|
@@ -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
|
|
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,
|
|
37
|
+
assert(identity('index', context.id, heading));
|
|
38
38
|
return [
|
|
39
|
-
html('aside', { id: identity(context.id,
|
|
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)))])
|
|
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)))])
|
|
29
|
+
ns => [html('li', defrag(fillFirstLine(ns)))])),
|
|
30
30
|
])))),
|
|
31
31
|
es => [format(html('ul', es))])));
|
|
32
32
|
|
package/src/parser/block.ts
CHANGED
|
@@ -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,
|
package/src/parser/context.ts
CHANGED
|
@@ -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 ]')), [['<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|©]')), [['<a class="index" href="#index::&copy;">a<span class="indexer" data-index="&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
|
|
8
|
-
export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context
|
|
9
|
-
return fmap(parser, ([el], _, { id }) => [define(el, { id: identity(id,
|
|
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 (
|
|
29
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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	==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	==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)
|
|
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
|
-
|
|
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,
|