securemark 0.297.5 → 0.297.7
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 +74 -44
- package/package.json +1 -1
- package/src/parser/api/parse.test.ts +13 -13
- package/src/parser/block/table.test.ts +1 -1
- package/src/parser/context.ts +7 -3
- package/src/parser/inline/annotation.test.ts +11 -5
- package/src/parser/inline/annotation.ts +41 -19
- package/src/parser/inline/bracket.test.ts +7 -6
- package/src/parser/inline/bracket.ts +4 -4
- package/src/parser/inline/extension/indexee.ts +1 -0
- package/src/parser/inline/reference.test.ts +4 -0
- package/src/parser/inline/reference.ts +4 -5
- package/src/parser/inline.test.ts +3 -3
- package/src/parser/processor/note.test.ts +15 -37
- package/src/parser/processor/note.ts +5 -1
- package/src/renderer/render.ts +0 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.297.
|
|
1
|
+
/*! securemark v0.297.7 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"));
|
|
@@ -6111,7 +6111,7 @@ const parser_1 = __webpack_require__(605);
|
|
|
6111
6111
|
class Context extends parser_1.Context {
|
|
6112
6112
|
constructor(options = {}) {
|
|
6113
6113
|
super(options);
|
|
6114
|
-
this.recursion = new RecursionCounter(
|
|
6114
|
+
this.recursion = new RecursionCounter('annotation', 2);
|
|
6115
6115
|
const {
|
|
6116
6116
|
segment,
|
|
6117
6117
|
buffer,
|
|
@@ -6134,7 +6134,8 @@ class Context extends parser_1.Context {
|
|
|
6134
6134
|
}
|
|
6135
6135
|
exports.Context = Context;
|
|
6136
6136
|
class RecursionCounter {
|
|
6137
|
-
constructor(limit) {
|
|
6137
|
+
constructor(syntax, limit) {
|
|
6138
|
+
this.syntax = syntax;
|
|
6138
6139
|
this.limit = limit;
|
|
6139
6140
|
this.stack = [];
|
|
6140
6141
|
this.index = 0;
|
|
@@ -6144,7 +6145,8 @@ class RecursionCounter {
|
|
|
6144
6145
|
stack
|
|
6145
6146
|
} = this;
|
|
6146
6147
|
for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
|
|
6147
|
-
|
|
6148
|
+
// 内側から数えるので無効化処理できずエラーを投げるしかない。
|
|
6149
|
+
if (this.index === this.limit) throw new Error(`Too much ${this.syntax} recursion`);
|
|
6148
6150
|
stack[this.index] = depth;
|
|
6149
6151
|
++this.index;
|
|
6150
6152
|
}
|
|
@@ -6377,36 +6379,48 @@ const dom_1 = __webpack_require__(394);
|
|
|
6377
6379
|
// 動的計画法を適用するか再帰数を制限する必要がある。
|
|
6378
6380
|
// 動的計画法においては再帰的記録により指数空間計算量にならないよう下位の記録を消しながら記録しなければならない。
|
|
6379
6381
|
// トリムも再帰的に行わないよう前後のトリムサイズの記録を要する。
|
|
6380
|
-
//
|
|
6382
|
+
// しかし理論的には無制限の再帰が可能だがホバーテキストの記録やハッシュの計算を行う言語仕様から指数計算量を
|
|
6381
6383
|
// 避けられないためAnnotation構文に限り再帰数の制限が必要となる。
|
|
6382
|
-
//
|
|
6384
|
+
// シグネチャやハッシュは分割計算可能にすれば解決するがホバーテキストは記録せず動的に再計算して
|
|
6383
6385
|
// 表示しなければ指数空間計算量を避けられない。
|
|
6384
|
-
//
|
|
6386
|
+
// 注釈を除外すると重複排除により参照元が消滅し欠番が生じるため少なくとも直接注釈は残す必要があるが間接注釈は
|
|
6387
|
+
// 除外できる。しかしこれを効率的に行うことは難しいため最大再帰数を1回に制限することで間接注釈を行えない
|
|
6388
|
+
// ようにするのが合理的だろう。
|
|
6389
|
+
// 原理的には逆順処理により圧縮後正順で再附番すればすべて解決するはずだがテキストとシグネチャとハッシュも
|
|
6390
|
+
// 修正する必要があるためほぼ完全な二重処理が必要になり三重以上の注釈という不適切な使用のために
|
|
6391
|
+
// 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
|
|
6392
|
+
const MAX_DEPTH = 20;
|
|
6385
6393
|
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, combinator_1.surround)((0, combinator_1.open)('((', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.recursions)([4 /* Recursion.annotation */, 3 /* Recursion.inline */, 5 /* Recursion.bracket */, 5 /* Recursion.bracket */], (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]))), '))', false, [], ([, ns], context) => {
|
|
6386
6394
|
const {
|
|
6387
|
-
linebreak
|
|
6395
|
+
linebreak,
|
|
6396
|
+
recursion,
|
|
6397
|
+
resources
|
|
6388
6398
|
} = context;
|
|
6389
|
-
if (linebreak
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
}, (
|
|
6399
|
+
if (linebreak !== 0) {
|
|
6400
|
+
ns.unshift(new parser_1.Node('('));
|
|
6401
|
+
ns.push(new parser_1.Node(')'));
|
|
6402
|
+
return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6403
|
+
class: 'bracket'
|
|
6404
|
+
}, ['(', (0, dom_1.html)('span', {
|
|
6405
|
+
class: 'bracket'
|
|
6406
|
+
}, (0, dom_1.defrag)((0, util_1.unwrap)(ns))), ')']))]);
|
|
6407
|
+
}
|
|
6408
|
+
const depth = MAX_DEPTH - (resources?.recursions[4 /* Recursion.annotation */] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
|
|
6409
|
+
recursion.add(depth);
|
|
6410
|
+
return new parser_1.List([new parser_1.Node((0, dom_1.html)('sup', {
|
|
6411
|
+
class: 'annotation'
|
|
6412
|
+
}, [(0, dom_1.html)('span', (0, dom_1.defrag)((0, util_1.unwrap)((0, visibility_1.trimBlankNodeEnd)(ns))))]))]);
|
|
6413
|
+
}, ([, bs], context) => {
|
|
6403
6414
|
const {
|
|
6404
6415
|
source,
|
|
6405
6416
|
position,
|
|
6406
6417
|
range,
|
|
6407
|
-
linebreak
|
|
6418
|
+
linebreak,
|
|
6419
|
+
recursion,
|
|
6420
|
+
resources
|
|
6408
6421
|
} = context;
|
|
6409
|
-
|
|
6422
|
+
const depth = MAX_DEPTH - (resources?.recursions[4 /* Recursion.annotation */] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
|
|
6423
|
+
if (linebreak === 0 && bs && bs.length === 1 && source[position] === ')' && typeof bs.head?.value === 'object') {
|
|
6410
6424
|
const {
|
|
6411
6425
|
className
|
|
6412
6426
|
} = bs.head.value;
|
|
@@ -6426,7 +6440,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
|
|
|
6426
6440
|
lastChild.nodeValue = lastChild.nodeValue.slice(0, -1);
|
|
6427
6441
|
}
|
|
6428
6442
|
context.position += 1;
|
|
6429
|
-
|
|
6443
|
+
recursion.add(depth);
|
|
6430
6444
|
return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6431
6445
|
class: 'bracket'
|
|
6432
6446
|
}, ['(', (0, dom_1.html)('sup', {
|
|
@@ -6435,7 +6449,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
|
|
|
6435
6449
|
}
|
|
6436
6450
|
if (className === 'annotation' && deepunwrap(bs)) {
|
|
6437
6451
|
context.position += 1;
|
|
6438
|
-
|
|
6452
|
+
recursion.add(depth);
|
|
6439
6453
|
return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6440
6454
|
class: 'bracket'
|
|
6441
6455
|
}, ['(', (0, dom_1.html)('sup', {
|
|
@@ -6443,19 +6457,32 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
|
|
|
6443
6457
|
}, [(0, dom_1.html)('span', [bs.head.value])])]))]);
|
|
6444
6458
|
}
|
|
6445
6459
|
}
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6460
|
+
bs ??= new parser_1.List();
|
|
6461
|
+
bs.unshift(new parser_1.Node('('));
|
|
6462
|
+
if (source[context.position] === ')') {
|
|
6463
|
+
bs.push(new parser_1.Node(')'));
|
|
6464
|
+
context.position += 1;
|
|
6451
6465
|
}
|
|
6466
|
+
const str = linebreak === 0 ? source.slice(position - range + 2, position) : '';
|
|
6467
|
+
bs = linebreak === 0 && (str === '' || bracket_1.indexA.test(str)) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6468
|
+
class: 'paren'
|
|
6469
|
+
}, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]) : new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6470
|
+
class: 'bracket'
|
|
6471
|
+
}, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]);
|
|
6452
6472
|
bs.unshift(new parser_1.Node('('));
|
|
6473
|
+
const cs = parser({
|
|
6474
|
+
context
|
|
6475
|
+
});
|
|
6476
|
+
if (source[context.position] === ')') {
|
|
6477
|
+
cs && bs.import(cs);
|
|
6478
|
+
bs.push(new parser_1.Node(')'));
|
|
6479
|
+
context.position += 1;
|
|
6480
|
+
}
|
|
6453
6481
|
return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6454
6482
|
class: 'bracket'
|
|
6455
|
-
},
|
|
6456
|
-
class: 'bracket'
|
|
6457
|
-
}, (0, dom_1.defrag)((0, util_1.unwrap)(bs)))]))]);
|
|
6483
|
+
}, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]);
|
|
6458
6484
|
})));
|
|
6485
|
+
const parser = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(1, (0, combinator_1.some)(inline_1.inline, ')', [[')', 1]])));
|
|
6459
6486
|
function deepunwrap(list) {
|
|
6460
6487
|
let bottom = list.head.value;
|
|
6461
6488
|
for (; bottom;) {
|
|
@@ -6786,7 +6813,7 @@ const p1 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.
|
|
|
6786
6813
|
linebreak
|
|
6787
6814
|
}) => {
|
|
6788
6815
|
const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
|
|
6789
|
-
return linebreak === 0 && exports.indexA.test(str) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6816
|
+
return linebreak === 0 && (str === '' || exports.indexA.test(str)) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6790
6817
|
class: 'paren'
|
|
6791
6818
|
}, `(${str})`))]) : new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6792
6819
|
class: 'bracket'
|
|
@@ -6799,7 +6826,7 @@ const p1 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.
|
|
|
6799
6826
|
linebreak
|
|
6800
6827
|
} = context;
|
|
6801
6828
|
const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
|
|
6802
|
-
return linebreak === 0 && exports.indexA.test(str) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6829
|
+
return linebreak === 0 && (str === '' || exports.indexA.test(str)) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6803
6830
|
class: 'paren'
|
|
6804
6831
|
}, `(${str}`))]) : new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6805
6832
|
class: 'bracket'
|
|
@@ -6812,7 +6839,7 @@ const p2 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.
|
|
|
6812
6839
|
linebreak
|
|
6813
6840
|
}) => {
|
|
6814
6841
|
const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
|
|
6815
|
-
return linebreak === 0 && indexF.test(str) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6842
|
+
return linebreak === 0 && (str === '' || indexF.test(str)) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6816
6843
|
class: 'paren'
|
|
6817
6844
|
}, `(${str})`))]) : new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6818
6845
|
class: 'bracket'
|
|
@@ -6825,7 +6852,7 @@ const p2 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.
|
|
|
6825
6852
|
linebreak
|
|
6826
6853
|
} = context;
|
|
6827
6854
|
const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
|
|
6828
|
-
return linebreak === 0 && indexF.test(str) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6855
|
+
return linebreak === 0 && (str === '' || indexF.test(str)) ? new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6829
6856
|
class: 'paren'
|
|
6830
6857
|
}, `(${str}`))]) : new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
6831
6858
|
class: 'bracket'
|
|
@@ -7946,12 +7973,12 @@ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64
|
|
|
7946
7973
|
range,
|
|
7947
7974
|
linebreak
|
|
7948
7975
|
} = context;
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
} else {
|
|
7952
|
-
const head = position - range;
|
|
7976
|
+
const head = position - range;
|
|
7977
|
+
if (linebreak !== 0) {
|
|
7953
7978
|
(0, combinator_1.setBacktrack)(context, 2 | 64 /* Backtrack.link */, head, 2);
|
|
7979
|
+
return;
|
|
7954
7980
|
}
|
|
7981
|
+
return new parser_1.List([new parser_1.Node((0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)((0, util_1.unwrap)((0, visibility_1.trimBlankNodeEnd)(ns))))]))]);
|
|
7955
7982
|
}, (_, context) => {
|
|
7956
7983
|
const {
|
|
7957
7984
|
source,
|
|
@@ -8466,6 +8493,9 @@ function build(syntax, list, query, marker, splitter = '') {
|
|
|
8466
8493
|
'data-marker': note ? undefined : marker(total + defs.size + 1, abbr)
|
|
8467
8494
|
}, [content, (0, dom_1.html)('sup')]) : defs.get(identifier);
|
|
8468
8495
|
initial && defs.set(identifier, def);
|
|
8496
|
+
if (!initial && content.innerHTML.length > def.firstElementChild.innerHTML.length) {
|
|
8497
|
+
def.firstElementChild.replaceWith(content);
|
|
8498
|
+
}
|
|
8469
8499
|
const defIndex = initial ? info.defIndex = total + defs.size : info.defIndex;
|
|
8470
8500
|
const title = info.title ||= text;
|
|
8471
8501
|
(0, dom_1.define)(ref, {
|
|
@@ -8498,13 +8528,14 @@ function build(syntax, list, query, marker, splitter = '') {
|
|
|
8498
8528
|
info.queue.push(ref);
|
|
8499
8529
|
break;
|
|
8500
8530
|
}
|
|
8501
|
-
|
|
8531
|
+
ref.appendChild((0, dom_1.html)('a', {
|
|
8502
8532
|
href: refId && defId && `#${defId}`
|
|
8503
8533
|
}, marker(defIndex, abbr)));
|
|
8504
8534
|
def.lastElementChild.appendChild((0, dom_1.html)('a', {
|
|
8505
8535
|
href: refId && `#${refId}`,
|
|
8506
8536
|
title: abbr && text || undefined
|
|
8507
8537
|
}, `^${++refIndex}`));
|
|
8538
|
+
yield;
|
|
8508
8539
|
}
|
|
8509
8540
|
if (note || defs.size > 0) {
|
|
8510
8541
|
const splitter = splitters[iSplitters++];
|
|
@@ -9467,7 +9498,6 @@ function render(source, opts = {}) {
|
|
|
9467
9498
|
}
|
|
9468
9499
|
exports.render = render;
|
|
9469
9500
|
function render_(base, source, opts) {
|
|
9470
|
-
if (source.classList.contains('invalid')) return;
|
|
9471
9501
|
try {
|
|
9472
9502
|
switch (true) {
|
|
9473
9503
|
case !!opts.code && !source.firstElementChild && source.matches('pre.code'):
|
package/package.json
CHANGED
|
@@ -307,7 +307,7 @@ describe('Unit: parser/api/parse', () => {
|
|
|
307
307
|
// ]);
|
|
308
308
|
assert.deepStrictEqual(
|
|
309
309
|
[...parse(`${'('.repeat(20)}0`).children].map(el => el.outerHTML),
|
|
310
|
-
[`<p>${'<span class="bracket">('.repeat(19)}(0
|
|
310
|
+
[`<p>${'<span class="bracket">('.repeat(19)}<span class="paren">(0</span>${'</span>'.repeat(19)}</p>`]);
|
|
311
311
|
assert.deepStrictEqual(
|
|
312
312
|
[...parse(`${'('.repeat(21)}0`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
313
313
|
[
|
|
@@ -324,40 +324,40 @@ describe('Unit: parser/api/parse', () => {
|
|
|
324
324
|
`<pre class="error" translate="no">${'['.repeat(21)}0</pre>`,
|
|
325
325
|
]);
|
|
326
326
|
assert.deepStrictEqual(
|
|
327
|
-
[...parse(`${'(('.repeat(
|
|
327
|
+
[...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
328
328
|
['P', 'OL']);
|
|
329
329
|
assert.deepStrictEqual(
|
|
330
|
-
[...parse(`${'(('.repeat(
|
|
330
|
+
[...parse(`${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
331
331
|
['H1', 'PRE']);
|
|
332
332
|
assert.deepStrictEqual(
|
|
333
|
-
[...parse(`${'(('.repeat(
|
|
333
|
+
[...parse(`${'(('.repeat(2)}!${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
334
334
|
['P', 'OL']);
|
|
335
335
|
assert.deepStrictEqual(
|
|
336
|
-
[...parse(`${'(('.repeat(
|
|
336
|
+
[...parse(`${'(('.repeat(3)}!${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
337
337
|
['H1', 'PRE']);
|
|
338
338
|
assert.deepStrictEqual(
|
|
339
|
-
[...parse(`(${'(('.repeat(
|
|
339
|
+
[...parse(`(${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
340
340
|
['P', 'OL']);
|
|
341
341
|
assert.deepStrictEqual(
|
|
342
|
-
[...parse(`(${'(('.repeat(
|
|
342
|
+
[...parse(`(${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
343
343
|
['H1', 'PRE']);
|
|
344
344
|
assert.deepStrictEqual(
|
|
345
|
-
[...parse(`(${'(('.repeat(
|
|
345
|
+
[...parse(`(${'(('.repeat(2)}!${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
346
346
|
['P', 'OL']);
|
|
347
347
|
assert.deepStrictEqual(
|
|
348
|
-
[...parse(`(${'(('.repeat(
|
|
348
|
+
[...parse(`(${'(('.repeat(3)}!${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
349
349
|
['H1', 'PRE']);
|
|
350
350
|
assert.deepStrictEqual(
|
|
351
|
-
[...parse(`${'(('.repeat(
|
|
351
|
+
[...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
352
352
|
['P', 'OL']);
|
|
353
353
|
assert.deepStrictEqual(
|
|
354
|
-
[...parse(`${'(('.repeat(
|
|
354
|
+
[...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
355
355
|
['H1', 'PRE']);
|
|
356
356
|
assert.deepStrictEqual(
|
|
357
|
-
[...parse(`${'(('.repeat(
|
|
357
|
+
[...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(9)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
|
|
358
358
|
['P', 'OL']);
|
|
359
359
|
assert.deepStrictEqual(
|
|
360
|
-
[...parse(`${'(('.repeat(
|
|
360
|
+
[...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(9)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
|
|
361
361
|
['H1', 'PRE']);
|
|
362
362
|
});
|
|
363
363
|
|
|
@@ -33,7 +33,7 @@ describe('Unit: parser/block/table', () => {
|
|
|
33
33
|
assert.deepStrictEqual(inspect(parser, input('|||\n|-|-|\n|||', new Context())), [['<table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td></td><td></td></tr></tbody></table>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser, input('|"|\n|-\n|', new Context())), [['<table><thead><tr><th>"</th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser, input('|`|`|\n|-\n|', new Context())), [['<table><thead><tr><th><code data-src="`|`">|</code></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="bracket">(<span class="
|
|
36
|
+
assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="bracket">(<span class="paren">(</span></span></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
|
|
37
37
|
assert.deepStrictEqual(inspect(parser, input('|a|b|\n|-|-|\n|1|2|', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
|
|
38
38
|
assert.deepStrictEqual(inspect(parser, input('|a|b\n|-|-\n|1|2', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
|
|
39
39
|
assert.deepStrictEqual(inspect(parser, input('|a|\n|-|\n|1|', new Context())), [['<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>'], '']);
|
package/src/parser/context.ts
CHANGED
|
@@ -28,7 +28,7 @@ export class Context extends Ctx {
|
|
|
28
28
|
public override segment: Segment;
|
|
29
29
|
public buffer: List<Node<(string | HTMLElement)>>;
|
|
30
30
|
public sequential: boolean;
|
|
31
|
-
public recursion = new RecursionCounter(
|
|
31
|
+
public recursion = new RecursionCounter('annotation', 2);
|
|
32
32
|
public readonly header: boolean;
|
|
33
33
|
public readonly host?: URL;
|
|
34
34
|
public readonly url?: URL;
|
|
@@ -42,14 +42,18 @@ export class Context extends Ctx {
|
|
|
42
42
|
export type Options = Partial<Context>;
|
|
43
43
|
|
|
44
44
|
class RecursionCounter {
|
|
45
|
-
constructor(
|
|
45
|
+
constructor(
|
|
46
|
+
private readonly syntax: string,
|
|
47
|
+
private readonly limit: number,
|
|
48
|
+
) {
|
|
46
49
|
}
|
|
47
50
|
private readonly stack: number[] = [];
|
|
48
51
|
private index = 0;
|
|
49
52
|
public add(depth: number): void {
|
|
50
53
|
const { stack } = this
|
|
51
54
|
for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
|
|
52
|
-
|
|
55
|
+
// 内側から数えるので無効化処理できずエラーを投げるしかない。
|
|
56
|
+
if (this.index === this.limit) throw new Error(`Too much ${this.syntax} recursion`);
|
|
53
57
|
stack[this.index] = depth;
|
|
54
58
|
++this.index;
|
|
55
59
|
}
|
|
@@ -13,9 +13,15 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('(', new Context())), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('()', new Context())), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('((', new Context())), undefined);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="bracket">(<span class="
|
|
17
|
-
assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="bracket">(<span class="
|
|
16
|
+
assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="bracket">(<span class="paren">()</span>)</span>'], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="bracket">(<span class="paren">()</span>)</span>'], ')']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="bracket">(<span class="bracket">("))</span></span>'], '']);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser, input('((a', new Context())), [['<span class="bracket">(<span class="paren">(a</span></span>'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser, input('((!', new Context())), [['<span class="bracket">(<span class="bracket">(!</span></span>'], '']);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser, input('((a)', new Context())), [['<span class="bracket">(<span class="paren">(a)</span></span>'], '']);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser, input('((!)', new Context())), [['<span class="bracket">(<span class="bracket">(!)</span></span>'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser, input('((a)b)', new Context())), [['<span class="bracket">(<span class="paren">(a)</span>b)</span>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser, input('((!)b)', new Context())), [['<span class="bracket">(<span class="bracket">(!)</span>b)</span>'], '']);
|
|
19
25
|
assert.deepStrictEqual(inspect(parser, input('(([))', new Context())), [['<span class="bracket">(<span class="bracket">([))</span></span>'], '']);
|
|
20
26
|
assert.deepStrictEqual(inspect(parser, input('(([%))', new Context())), [['<span class="bracket">(<span class="bracket">([%))</span></span>'], '']);
|
|
21
27
|
assert.deepStrictEqual(inspect(parser, input('(( ))', new Context())), undefined);
|
|
@@ -31,9 +37,7 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
31
37
|
assert.deepStrictEqual(inspect(parser, input('((a\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
|
|
32
38
|
assert.deepStrictEqual(inspect(parser, input('((a\\\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
|
|
33
39
|
assert.deepStrictEqual(inspect(parser, input('((*a\nb*))', new Context())), [['<span class="bracket">(<span class="bracket">(<em>a<br>b</em>)</span>)</span>'], '']);
|
|
34
|
-
assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="bracket">(<span class="bracket">()</span></span>'], '
|
|
35
|
-
assert.deepStrictEqual(inspect(parser, input('((a)b))', new Context())), [['<span class="bracket">((a</span>'], ')b))']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser, input('((!)b))', new Context())), [['<span class="bracket">(<span class="bracket">(!</span></span>'], ')b))']);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="bracket">(<span class="bracket">())</span></span>'], '']);
|
|
37
41
|
assert.deepStrictEqual(inspect(parser, input('(((a))', new Context())), [['<span class="bracket">(<sup class="annotation"><span>a</span></sup></span>'], '']);
|
|
38
42
|
assert.deepStrictEqual(inspect(parser, input('(((!))', new Context())), [['<span class="bracket">(<sup class="annotation"><span>!</span></sup></span>'], '']);
|
|
39
43
|
assert.deepStrictEqual(inspect(parser, input('(((*a*))', new Context())), [['<span class="bracket">(<sup class="annotation"><span><em>a</em></span></sup></span>'], '']);
|
|
@@ -57,6 +61,8 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
57
61
|
assert.deepStrictEqual(inspect(parser, input('((@a))', new Context())), [['<sup class="annotation"><span><a class="account" href="/@a">@a</a></span></sup>'], '']);
|
|
58
62
|
assert.deepStrictEqual(inspect(parser, input('((http://host))', new Context())), [['<sup class="annotation"><span><a class="url" href="http://host" target="_blank">http://host</a></span></sup>'], '']);
|
|
59
63
|
assert.deepStrictEqual(inspect(parser, input('((![]{a}))', new Context())), [['<sup class="annotation"><span>!<a class="url" href="a">a</a></span></sup>'], '']);
|
|
64
|
+
assert.deepStrictEqual(inspect(parser, input('((a(())))', new Context())), [['<sup class="annotation"><span>a<span class="bracket">(<span class="paren">()</span>)</span></span></sup>'], '']);
|
|
65
|
+
assert.deepStrictEqual(inspect(parser, input('((a[[]]))', new Context())), [['<sup class="annotation"><span>a[[]]</span></sup>'], '']);
|
|
60
66
|
assert.deepStrictEqual(inspect(parser, input('(([[a] ]))', new Context())), [['<sup class="annotation"><span>[[a] ]</span></sup>'], '']);
|
|
61
67
|
assert.deepStrictEqual(inspect(parser, input('(((a)))', new Context())), [['<sup class="annotation"><span><span class="paren">(a)</span></span></sup>'], '']);
|
|
62
68
|
assert.deepStrictEqual(inspect(parser, input('((((a))))', new Context())), [['<sup class="annotation"><span><sup class="annotation"><span>a</span></sup></span></sup>'], '']);
|
|
@@ -12,11 +12,17 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
12
12
|
// 動的計画法を適用するか再帰数を制限する必要がある。
|
|
13
13
|
// 動的計画法においては再帰的記録により指数空間計算量にならないよう下位の記録を消しながら記録しなければならない。
|
|
14
14
|
// トリムも再帰的に行わないよう前後のトリムサイズの記録を要する。
|
|
15
|
-
//
|
|
15
|
+
// しかし理論的には無制限の再帰が可能だがホバーテキストの記録やハッシュの計算を行う言語仕様から指数計算量を
|
|
16
16
|
// 避けられないためAnnotation構文に限り再帰数の制限が必要となる。
|
|
17
|
-
//
|
|
17
|
+
// シグネチャやハッシュは分割計算可能にすれば解決するがホバーテキストは記録せず動的に再計算して
|
|
18
18
|
// 表示しなければ指数空間計算量を避けられない。
|
|
19
|
-
//
|
|
19
|
+
// 注釈を除外すると重複排除により参照元が消滅し欠番が生じるため少なくとも直接注釈は残す必要があるが間接注釈は
|
|
20
|
+
// 除外できる。しかしこれを効率的に行うことは難しいため最大再帰数を1回に制限することで間接注釈を行えない
|
|
21
|
+
// ようにするのが合理的だろう。
|
|
22
|
+
// 原理的には逆順処理により圧縮後正順で再附番すればすべて解決するはずだがテキストとシグネチャとハッシュも
|
|
23
|
+
// 修正する必要があるためほぼ完全な二重処理が必要になり三重以上の注釈という不適切な使用のために
|
|
24
|
+
// 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
|
|
25
|
+
const MAX_DEPTH = 20;
|
|
20
26
|
export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, surround(
|
|
21
27
|
open('((', beforeNonblank),
|
|
22
28
|
precedence(1, recursions([Recursion.annotation, Recursion.inline, Recursion.bracket, Recursion.bracket],
|
|
@@ -24,18 +30,20 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
24
30
|
'))',
|
|
25
31
|
false, [],
|
|
26
32
|
([, ns], context) => {
|
|
27
|
-
const { linebreak } = context;
|
|
28
|
-
if (linebreak
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
const { linebreak, recursion, resources } = context;
|
|
34
|
+
if (linebreak !== 0) {
|
|
35
|
+
ns.unshift(new Node('('));
|
|
36
|
+
ns.push(new Node(')'));
|
|
37
|
+
return new List([new Node(html('span', { class: 'bracket' }, ['(', html('span', { class: 'bracket' }, defrag(unwrap(ns))), ')']))]);
|
|
31
38
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return new List([new Node(html('
|
|
39
|
+
const depth = MAX_DEPTH - (resources?.recursions[Recursion.annotation] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
|
|
40
|
+
recursion.add(depth);
|
|
41
|
+
return new List([new Node(html('sup', { class: 'annotation' }, [html('span', defrag(unwrap(trimBlankNodeEnd(ns))))]))]);
|
|
35
42
|
},
|
|
36
|
-
([, bs
|
|
37
|
-
const { source, position, range, linebreak } = context;
|
|
38
|
-
|
|
43
|
+
([, bs], context) => {
|
|
44
|
+
const { source, position, range, linebreak, recursion, resources } = context;
|
|
45
|
+
const depth = MAX_DEPTH - (resources?.recursions[Recursion.annotation] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
|
|
46
|
+
if (linebreak === 0 && bs && bs.length === 1 && source[position] === ')' && typeof bs.head?.value === 'object') {
|
|
39
47
|
const { className } = bs.head.value;
|
|
40
48
|
if (className === 'paren' || className === 'bracket') {
|
|
41
49
|
const { firstChild, lastChild } = bs.head.value;
|
|
@@ -54,23 +62,37 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
54
62
|
lastChild!.nodeValue = lastChild!.nodeValue!.slice(0, -1);
|
|
55
63
|
}
|
|
56
64
|
context.position += 1;
|
|
57
|
-
|
|
65
|
+
recursion.add(depth);
|
|
58
66
|
return new List([new Node(html('span', { class: 'bracket' }, ['(', html('sup', { class: 'annotation' }, [html('span', bs.head.value.childNodes)])]))]);
|
|
59
67
|
}
|
|
60
68
|
if (className === 'annotation' && deepunwrap(bs)) {
|
|
61
69
|
context.position += 1;
|
|
62
|
-
|
|
70
|
+
recursion.add(depth);
|
|
63
71
|
return new List([new Node(html('span', { class: 'bracket' }, ['(', html('sup', { class: 'annotation' }, [html('span', [bs.head.value])])]))]);
|
|
64
72
|
}
|
|
65
73
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
bs ??= new List();
|
|
75
|
+
bs.unshift(new Node('('));
|
|
76
|
+
if (source[context.position] === ')') {
|
|
77
|
+
bs.push(new Node(')'));
|
|
78
|
+
context.position += 1;
|
|
69
79
|
}
|
|
80
|
+
const str = linebreak === 0 ? source.slice(position - range + 2, position) : '';
|
|
81
|
+
bs = linebreak === 0 && (str === '' || indexA.test(str))
|
|
82
|
+
? new List([new Node(html('span', { class: 'paren' }, defrag(unwrap(bs))))])
|
|
83
|
+
: new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(bs))))]);
|
|
70
84
|
bs.unshift(new Node('('));
|
|
71
|
-
|
|
85
|
+
const cs = parser({ context });
|
|
86
|
+
if (source[context.position] === ')') {
|
|
87
|
+
cs && bs.import(cs);
|
|
88
|
+
bs.push(new Node(')'));
|
|
89
|
+
context.position += 1;
|
|
90
|
+
}
|
|
91
|
+
return new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(bs))))]);
|
|
72
92
|
})));
|
|
73
93
|
|
|
94
|
+
const parser = lazy(() => precedence(1, some(inline, ')', [[')', 1]])));
|
|
95
|
+
|
|
74
96
|
function deepunwrap(list: List<Node<string | HTMLElement>>): boolean {
|
|
75
97
|
let bottom = list.head!.value as HTMLElement;
|
|
76
98
|
for (; bottom;) {
|
|
@@ -9,8 +9,8 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
9
9
|
const parser = some(bracket);
|
|
10
10
|
|
|
11
11
|
it('(', () => {
|
|
12
|
-
assert.deepStrictEqual(inspect(parser, input('(', new Context())), [['<span class="
|
|
13
|
-
assert.deepStrictEqual(inspect(parser, input('()', new Context())), [['<span class="
|
|
12
|
+
assert.deepStrictEqual(inspect(parser, input('(', new Context())), [['<span class="paren">(</span>'], '']);
|
|
13
|
+
assert.deepStrictEqual(inspect(parser, input('()', new Context())), [['<span class="paren">()</span>'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('(a', new Context())), [['<span class="paren">(a</span>'], '']);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('(0)', new Context())), [['<span class="paren">(0)</span>'], '']);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('(1)', new Context())), [['<span class="paren">(1)</span>'], '']);
|
|
@@ -41,7 +41,8 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
41
41
|
assert.deepStrictEqual(inspect(parser, input('(ABBR, ABBR)', new Context())), [['<span class="paren">(ABBR, ABBR)</span>'], '']);
|
|
42
42
|
assert.deepStrictEqual(inspect(parser, input('(\\a)', new Context())), [['<span class="bracket">(a)</span>'], '']);
|
|
43
43
|
assert.deepStrictEqual(inspect(parser, input('(==)', new Context())), [['<span class="bracket">(==)</span>'], '']);
|
|
44
|
-
assert.deepStrictEqual(inspect(parser, input('(
|
|
44
|
+
assert.deepStrictEqual(inspect(parser, input('(()', new Context())), [['<span class="bracket">(<span class="paren">()</span></span>'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser, input('("(\n))"(")', new Context())), [['<span class="bracket">("<span class="paren">(</span><br>)</span>'], ')"(")']);
|
|
45
46
|
assert.deepStrictEqual(inspect(parser, input('($)$', new Context())), [['<span class="bracket">(<span class="math" translate="no" data-src="$)$">$)$</span></span>'], '']);
|
|
46
47
|
assert.deepStrictEqual(inspect(parser, input(')', new Context())), undefined);
|
|
47
48
|
assert.deepStrictEqual(inspect(parser, input('(1,2)', new Context())), [['<span class="paren">(1,2)</span>'], '']);
|
|
@@ -80,10 +81,10 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
80
81
|
assert.deepStrictEqual(inspect(parser, input('""', new Context())), [['"', '"'], '']);
|
|
81
82
|
assert.deepStrictEqual(inspect(parser, input('"a', new Context())), [['"', 'a'], '']);
|
|
82
83
|
assert.deepStrictEqual(inspect(parser, input('"a"', new Context())), [['"', 'a', '"'], '']);
|
|
83
|
-
assert.deepStrictEqual(inspect(parser, input('"(")"', new Context())), [['"', '<span class="
|
|
84
|
-
assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="bracket">(<span class="
|
|
84
|
+
assert.deepStrictEqual(inspect(parser, input('"(")"', new Context())), [['"', '<span class="paren">(</span>', '"'], ')"']);
|
|
85
|
+
assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="bracket">(<span class="paren">(</span></span>', '"'], '']);
|
|
85
86
|
assert.deepStrictEqual(inspect(parser, input('"(\\")"', new Context())), [['"', '<span class="bracket">(")</span>', '"'], '']);
|
|
86
|
-
assert.deepStrictEqual(inspect(parser, input('"(\n)"(")', new Context())), [['"', '<span class="
|
|
87
|
+
assert.deepStrictEqual(inspect(parser, input('"(\n)"(")', new Context())), [['"', '<span class="paren">(</span>'], '\n)"(")']);
|
|
87
88
|
assert.deepStrictEqual(inspect(parser, input('"\n"', new Context())), [['"'], '\n"']);
|
|
88
89
|
assert.deepStrictEqual(inspect(parser, input('"\n"(")', new Context())), [['"'], '\n"(")']);
|
|
89
90
|
});
|
|
@@ -41,14 +41,14 @@ const p1 = lazy(() => surround(
|
|
|
41
41
|
true, [],
|
|
42
42
|
([as, bs = [], cs], { source, position, range, linebreak }) => {
|
|
43
43
|
const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
|
|
44
|
-
return linebreak === 0 && indexA.test(str)
|
|
44
|
+
return linebreak === 0 && (str === '' || indexA.test(str))
|
|
45
45
|
? new List([new Node(html('span', { class: 'paren' }, `(${str})`))])
|
|
46
46
|
: new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
|
|
47
47
|
},
|
|
48
48
|
([as, bs = new List()], context) => {
|
|
49
49
|
const { source, position, range, linebreak } = context;
|
|
50
50
|
const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
|
|
51
|
-
return linebreak === 0 && indexA.test(str)
|
|
51
|
+
return linebreak === 0 && (str === '' || indexA.test(str))
|
|
52
52
|
? new List([new Node(html('span', { class: 'paren' }, `(${str}`))])
|
|
53
53
|
: new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
|
|
54
54
|
}));
|
|
@@ -60,14 +60,14 @@ const p2 = lazy(() => surround(
|
|
|
60
60
|
true, [],
|
|
61
61
|
([as, bs = [], cs], { source, position, range, linebreak }) => {
|
|
62
62
|
const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
|
|
63
|
-
return linebreak === 0 && indexF.test(str)
|
|
63
|
+
return linebreak === 0 && (str === '' || indexF.test(str))
|
|
64
64
|
? new List([new Node(html('span', { class: 'paren' }, `(${str})`))])
|
|
65
65
|
: new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
|
|
66
66
|
},
|
|
67
67
|
([as, bs = new List()], context) => {
|
|
68
68
|
const { source, position, range, linebreak } = context;
|
|
69
69
|
const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
|
|
70
|
-
return linebreak === 0 && indexF.test(str)
|
|
70
|
+
return linebreak === 0 && (str === '' || indexF.test(str))
|
|
71
71
|
? new List([new Node(html('span', { class: 'paren' }, `(${str}`))])
|
|
72
72
|
: new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
|
|
73
73
|
}));
|
|
@@ -15,6 +15,7 @@ const MAX = 60;
|
|
|
15
15
|
const ELLIPSIS = '...';
|
|
16
16
|
const PART = (MAX - ELLIPSIS.length) / 2 | 0;
|
|
17
17
|
const REM = MAX - PART * 2 - ELLIPSIS.length;
|
|
18
|
+
assert(PART * 2 + REM + ELLIPSIS.length === MAX);
|
|
18
19
|
const table = [
|
|
19
20
|
...[...Array(36)].map((_, i) => i.toString(36)),
|
|
20
21
|
...[...Array(36)].map((_, i) => i.toString(36).toUpperCase()).slice(-26),
|
|
@@ -15,6 +15,9 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('[[', new Context())), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('[[]]', new Context())), undefined);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser, input('[[]]]', new Context())), undefined);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser, input('[[a', new Context())), undefined);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser, input('[[a]', new Context())), undefined);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser, input('[[a]b]', new Context())), undefined);
|
|
18
21
|
assert.deepStrictEqual(inspect(parser, input('[["]]', new Context())), undefined);
|
|
19
22
|
assert.deepStrictEqual(inspect(parser, input('[[(]]', new Context())), undefined);
|
|
20
23
|
assert.deepStrictEqual(inspect(parser, input('[[[%]]', new Context())), undefined);
|
|
@@ -51,6 +54,7 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
51
54
|
assert.deepStrictEqual(inspect(parser, input('[[@a]]', new Context())), [['<sup class="reference"><span><a class="account" href="/@a">@a</a></span></sup>'], '']);
|
|
52
55
|
assert.deepStrictEqual(inspect(parser, input('[[http://host]]', new Context())), [['<sup class="reference"><span><a class="url" href="http://host" target="_blank">http://host</a></span></sup>'], '']);
|
|
53
56
|
assert.deepStrictEqual(inspect(parser, input('[[![]{a}]]', new Context())), [['<sup class="reference"><span>!<a class="url" href="a">a</a></span></sup>'], '']);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser, input('[[a[[]]]]', new Context())), [['<sup class="reference"><span>a[[]]</span></sup>'], '']);
|
|
54
58
|
assert.deepStrictEqual(inspect(parser, input('[[[a]]]', new Context())), [['<sup class="reference"><span>[a]</span></sup>'], '']);
|
|
55
59
|
assert.deepStrictEqual(inspect(parser, input('[[[[a]]]]', new Context())), [['<sup class="reference"><span>[[a]]</span></sup>'], '']);
|
|
56
60
|
assert.deepStrictEqual(inspect(parser, input('[[((a))]]', new Context())), [['<sup class="reference"><span><span class="bracket">(<span class="paren">(a)</span>)</span></span></sup>'], '']);
|
|
@@ -21,13 +21,12 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
|
|
|
21
21
|
[2, 1 | Backtrack.common, 3 | Backtrack.doublebracket],
|
|
22
22
|
([, ns], context) => {
|
|
23
23
|
const { position, range, linebreak } = context;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
const head = position - range;
|
|
24
|
+
const head = position - range;
|
|
25
|
+
if (linebreak !== 0) {
|
|
29
26
|
setBacktrack(context, 2 | Backtrack.link, head, 2);
|
|
27
|
+
return;
|
|
30
28
|
}
|
|
29
|
+
return new List([new Node(html('sup', attributes(ns), [html('span', defrag(unwrap(trimBlankNodeEnd(ns))))]))]);
|
|
31
30
|
},
|
|
32
31
|
(_, context): undefined => {
|
|
33
32
|
const { source, position, range, linebreak } = context;
|
|
@@ -83,11 +83,11 @@ describe('Unit: parser/inline', () => {
|
|
|
83
83
|
assert.deepStrictEqual(inspect(parser, input('*++ a ++*', new Context())), [['<em><ins> a </ins></em>'], '']);
|
|
84
84
|
assert.deepStrictEqual(inspect(parser, input('*<bdi>`a`</bdi>*', new Context())), [['<em><bdi><code data-src="`a`">a</code></bdi></em>'], '']);
|
|
85
85
|
assert.deepStrictEqual(inspect(parser, input('*a"\nb*', new Context())), [['<em>a"<br>b</em>'], '']);
|
|
86
|
-
assert.deepStrictEqual(inspect(parser, input('*a"\n"("b*', new Context())), [['<em>a"<br>"<span class="
|
|
86
|
+
assert.deepStrictEqual(inspect(parser, input('*a"\n"("b*', new Context())), [['<em>a"<br>"<span class="paren">(</span>"b</em>'], '']);
|
|
87
87
|
assert.deepStrictEqual(inspect(parser, input('"*a\nb*', new Context())), [['"', '*', 'a', '<br>', 'b', '*'], '']);
|
|
88
88
|
assert.deepStrictEqual(inspect(parser, input('"*a\n""b*', new Context())), [['"', '*', 'a', '<br>', '"', '"', 'b', '*'], '']);
|
|
89
89
|
assert.deepStrictEqual(inspect(parser, input('"a\n"*b"c*', new Context())), [['"', 'a', '<br>', '"', '*', 'b', '"', 'c', '*'], '']);
|
|
90
|
-
assert.deepStrictEqual(inspect(parser, input('"*a**b\nc**"("*', new Context())), [['"', '*', 'a', '**', 'b', '<br>', 'c', '**', '"', '<span class="
|
|
90
|
+
assert.deepStrictEqual(inspect(parser, input('"*a**b\nc**"("*', new Context())), [['"', '*', 'a', '**', 'b', '<br>', 'c', '**', '"', '<span class="paren">(</span>', '"', '*'], '']);
|
|
91
91
|
assert.deepStrictEqual(inspect(parser, input('[% a"\nb %]', new Context())), [['<span class="remark"><input type="checkbox"><span>[% a"<br>b %]</span></span>'], '']);
|
|
92
92
|
assert.deepStrictEqual(inspect(parser, input('"<bdi>"a\n""b</bdi>"', new Context())), [['"', '<span class="invalid"><bdi></span>', '"', 'a', '<br>', '"', '"', 'b', '</bdi', '>', '"'], '']);
|
|
93
93
|
assert.deepStrictEqual(inspect(parser, input('<bdi>*<bdi>a</bdi>*</bdi>', new Context())), [['<bdi><em><bdi>a</bdi></em></bdi>'], '']);
|
|
@@ -140,7 +140,7 @@ describe('Unit: parser/inline', () => {
|
|
|
140
140
|
assert.deepStrictEqual(inspect(parser, input('(([["*(*"] ]))', new Context())), [['<sup class="annotation"><span>[["*<span class="bracket">(*</span>"] ]</span></sup>'], '']);
|
|
141
141
|
assert.deepStrictEqual(inspect(parser, input('(([:a\n]', new Context())), [['<span class="bracket">(<span class="bracket">(<span class="invalid">[:a\n]</span></span></span>'], '']);
|
|
142
142
|
assert.deepStrictEqual(inspect(parser, input('(({{\n}}', new Context())), [['<span class="bracket">(<span class="bracket">(<span class="template">{{<br>}}</span></span></span>'], '']);
|
|
143
|
-
assert.deepStrictEqual(inspect(parser, input('"((""))', new Context())), [['"', '<span class="bracket">(<span class="
|
|
143
|
+
assert.deepStrictEqual(inspect(parser, input('"((""))', new Context())), [['"', '<span class="bracket">(<span class="paren">(</span></span>', '"', '"', ')', ')'], '']);
|
|
144
144
|
assert.deepStrictEqual(inspect(parser, input('[[[a]]', new Context())), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
145
145
|
assert.deepStrictEqual(inspect(parser, input('[[[[a]]', new Context())), [['[', '[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
146
146
|
assert.deepStrictEqual(inspect(parser, input('[[[[a]]]]', new Context())), [['<sup class="reference"><span>[[a]]</span></sup>'], '']);
|
|
@@ -222,72 +222,50 @@ describe('Unit: parser/processor/note', () => {
|
|
|
222
222
|
});
|
|
223
223
|
|
|
224
224
|
it('nest', () => {
|
|
225
|
-
const target = parse('((a((b
|
|
225
|
+
const target = parse('((a((b))))((a))((b))');
|
|
226
226
|
for (let i = 0; i < 3; ++i) {
|
|
227
227
|
[...note(target)];
|
|
228
228
|
assert.deepStrictEqual(
|
|
229
229
|
[...target.children].map(el => el.outerHTML),
|
|
230
230
|
[
|
|
231
231
|
html('p', [
|
|
232
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:a((b
|
|
233
|
-
html('a', { href: '#annotation::def:a((b
|
|
232
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:a((b)):1', title: 'a((b))' }, [
|
|
233
|
+
html('a', { href: '#annotation::def:a((b)):1' }, '*1')
|
|
234
234
|
]),
|
|
235
235
|
html('sup', { class: 'annotation', id: 'annotation::ref:a:1', title: 'a' }, [
|
|
236
|
-
html('a', { href: '#annotation::def:a:1' }, '*
|
|
236
|
+
html('a', { href: '#annotation::def:a:1' }, '*3')
|
|
237
237
|
]),
|
|
238
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:b:
|
|
239
|
-
html('a', { href: '#annotation::def:b:1' }, '*
|
|
240
|
-
]),
|
|
241
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:c:2', title: 'c' }, [
|
|
242
|
-
html('a', { href: '#annotation::def:c:1' }, '*3')
|
|
238
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:b:2', title: 'b' }, [
|
|
239
|
+
html('a', { href: '#annotation::def:b:1' }, '*2')
|
|
243
240
|
]),
|
|
244
241
|
]).outerHTML,
|
|
245
242
|
html('ol', { class: 'annotations' }, [
|
|
246
|
-
html('li', { id: 'annotation::def:a((b
|
|
243
|
+
html('li', { id: 'annotation::def:a((b)):1', 'data-marker': '*1' }, [
|
|
247
244
|
html('span', [
|
|
248
245
|
'a',
|
|
249
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:b
|
|
250
|
-
html('a', { href: '#annotation::def:b
|
|
246
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:b:1', title: 'b' }, [
|
|
247
|
+
html('a', { href: '#annotation::def:b:1' }, '*2')
|
|
251
248
|
]),
|
|
252
249
|
]),
|
|
253
250
|
html('sup', [
|
|
254
|
-
html('a', { href: '#annotation::ref:a((b
|
|
251
|
+
html('a', { href: '#annotation::ref:a((b)):1' }, '^1'),
|
|
255
252
|
])
|
|
256
253
|
]),
|
|
257
|
-
html('li', { id: 'annotation::def:b
|
|
254
|
+
html('li', { id: 'annotation::def:b:1', 'data-marker': '*2' }, [
|
|
258
255
|
html('span', [
|
|
259
256
|
'b',
|
|
260
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:c:1', title: 'c' }, [
|
|
261
|
-
html('a', { href: '#annotation::def:c:1' }, '*3')
|
|
262
|
-
]),
|
|
263
|
-
]),
|
|
264
|
-
html('sup', [
|
|
265
|
-
html('a', { href: '#annotation::ref:b((c)):1' }, '^2'),
|
|
266
|
-
])
|
|
267
|
-
]),
|
|
268
|
-
html('li', { id: 'annotation::def:c:1', 'data-marker': '*3' }, [
|
|
269
|
-
html('span', [
|
|
270
|
-
'c',
|
|
271
257
|
]),
|
|
272
258
|
html('sup', [
|
|
273
|
-
html('a', { href: '#annotation::ref:
|
|
274
|
-
html('a', { href: '#annotation::ref:
|
|
259
|
+
html('a', { href: '#annotation::ref:b:1' }, '^2'),
|
|
260
|
+
html('a', { href: '#annotation::ref:b:2' }, '^4'),
|
|
275
261
|
])
|
|
276
262
|
]),
|
|
277
|
-
html('li', { id: 'annotation::def:a:1', 'data-marker': '*
|
|
263
|
+
html('li', { id: 'annotation::def:a:1', 'data-marker': '*3' }, [
|
|
278
264
|
html('span', [
|
|
279
265
|
'a',
|
|
280
266
|
]),
|
|
281
267
|
html('sup', [
|
|
282
|
-
html('a', { href: '#annotation::ref:a:1' }, '^
|
|
283
|
-
])
|
|
284
|
-
]),
|
|
285
|
-
html('li', { id: 'annotation::def:b:1', 'data-marker': '*5' }, [
|
|
286
|
-
html('span', [
|
|
287
|
-
'b',
|
|
288
|
-
]),
|
|
289
|
-
html('sup', [
|
|
290
|
-
html('a', { href: '#annotation::ref:b:1' }, '^5'),
|
|
268
|
+
html('a', { href: '#annotation::ref:a:1' }, '^3'),
|
|
291
269
|
])
|
|
292
270
|
]),
|
|
293
271
|
]).outerHTML,
|
|
@@ -154,6 +154,9 @@ function build(
|
|
|
154
154
|
: defs.get(identifier)!;
|
|
155
155
|
initial && defs.set(identifier, def);
|
|
156
156
|
assert(def.lastElementChild?.matches('sup'));
|
|
157
|
+
if (!initial && content.innerHTML.length > def.firstElementChild!.innerHTML.length) {
|
|
158
|
+
def.firstElementChild!.replaceWith(content);
|
|
159
|
+
}
|
|
157
160
|
const defIndex = initial
|
|
158
161
|
? info.defIndex = total + defs.size
|
|
159
162
|
: info.defIndex;
|
|
@@ -187,7 +190,7 @@ function build(
|
|
|
187
190
|
info.queue.push(ref);
|
|
188
191
|
break;
|
|
189
192
|
}
|
|
190
|
-
|
|
193
|
+
ref.appendChild(html('a', { href: refId && defId && `#${defId}` }, marker(defIndex, abbr)));
|
|
191
194
|
assert(ref.title || ref.matches('.invalid'));
|
|
192
195
|
def.lastElementChild!.appendChild(
|
|
193
196
|
html('a',
|
|
@@ -196,6 +199,7 @@ function build(
|
|
|
196
199
|
title: abbr && text || undefined,
|
|
197
200
|
},
|
|
198
201
|
`^${++refIndex}`));
|
|
202
|
+
yield;
|
|
199
203
|
}
|
|
200
204
|
if (note || defs.size > 0) {
|
|
201
205
|
const splitter = splitters[iSplitters++];
|
package/src/renderer/render.ts
CHANGED
|
@@ -19,7 +19,6 @@ export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function render_(base: string, source: HTMLElement, opts: RenderingOptions): void {
|
|
22
|
-
if (source.classList.contains('invalid')) return;
|
|
23
22
|
try {
|
|
24
23
|
switch (true) {
|
|
25
24
|
case !!opts.code
|