securemark 0.268.0 → 0.268.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +0 -4
- package/dist/index.js +77 -56
- package/package.json +5 -5
- package/src/parser/autolink.test.ts +1 -2
- package/src/parser/block/olist.test.ts +2 -2
- package/src/parser/block/olist.ts +45 -18
- package/src/parser/block/ulist.test.ts +1 -1
- package/src/parser/block/ulist.ts +4 -4
- package/src/parser/inline/extension/indexee.ts +5 -3
- package/src/parser/processor/figure.ts +1 -2
- package/src/parser/processor/footnote.test.ts +3 -3
- package/src/parser/processor/footnote.ts +22 -35
- package/src/util/info.ts +5 -3
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.268.
|
|
1
|
+
/*! securemark v0.268.2 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
|
|
2
2
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
3
3
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
4
4
|
module.exports = factory(require("Prism"), require("DOMPurify"));
|
|
@@ -5234,7 +5234,7 @@ const openers = {
|
|
|
5234
5234
|
'(': /^\(([0-9]*|[a-z]*)(?![^)\n])\)?(?:-(?!-)[0-9]*)*(?:$|\s)/
|
|
5235
5235
|
};
|
|
5236
5236
|
exports.olist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.validate)(new RegExp([/^([0-9]+|[a-z]+|[A-Z]+)(?:-[0-9]+)*\.(?=[^\S\n]|\n[^\S\n]*\S)/.source, /^\(([0-9]+|[a-z]+)\)(?:-[0-9]+)*(?=[^\S\n]|\n[^\S\n]*\S)/.source].join('|')), (0, combinator_1.state)(8 /* State.media */, exports.olist_))));
|
|
5237
|
-
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 =>
|
|
5237
|
+
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 => index(ms[1]), [])), (0, combinator_1.match)(openers['('], (0, memoize_1.memoize)(ms => list(type(ms[1]), '('), ms => index(ms[1]), []))])));
|
|
5238
5238
|
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, visibility_1.trimBlank)((0, visibility_1.visualize)((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_]))]), exports.invalid), ns => [(0, dom_1.html)('li', {
|
|
5239
5239
|
'data-marker': ns[0] || undefined
|
|
5240
5240
|
}, (0, dom_1.defrag)((0, ulist_1.fillFirstLine)((0, array_1.shift)(ns)[1])))]), true)]))), es => [format((0, dom_1.html)('ol', es), type, form)]);
|
|
@@ -5252,12 +5252,26 @@ exports.invalid = (0, combinator_1.rewrite)((0, combinator_1.inits)([source_1.co
|
|
|
5252
5252
|
source
|
|
5253
5253
|
}) => [['', (0, dom_1.html)('span', {
|
|
5254
5254
|
class: 'invalid',
|
|
5255
|
-
'data-invalid-syntax': '
|
|
5255
|
+
'data-invalid-syntax': 'list',
|
|
5256
5256
|
'data-invalid-type': 'syntax',
|
|
5257
5257
|
'data-invalid-message': 'Fix the indent or the head of the list item'
|
|
5258
5258
|
}, source.replace('\n', ''))], '']);
|
|
5259
|
-
function
|
|
5260
|
-
switch (
|
|
5259
|
+
function index(value) {
|
|
5260
|
+
switch (value) {
|
|
5261
|
+
case 'i':
|
|
5262
|
+
return 1;
|
|
5263
|
+
case 'a':
|
|
5264
|
+
return 2;
|
|
5265
|
+
case 'I':
|
|
5266
|
+
return 3;
|
|
5267
|
+
case 'A':
|
|
5268
|
+
return 4;
|
|
5269
|
+
default:
|
|
5270
|
+
return 0;
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
function type(value) {
|
|
5274
|
+
switch (value) {
|
|
5261
5275
|
case 'i':
|
|
5262
5276
|
return 'i';
|
|
5263
5277
|
case 'a':
|
|
@@ -5284,7 +5298,7 @@ function style(type) {
|
|
|
5284
5298
|
return '';
|
|
5285
5299
|
}
|
|
5286
5300
|
}
|
|
5287
|
-
function
|
|
5301
|
+
function pattern(type) {
|
|
5288
5302
|
switch (type) {
|
|
5289
5303
|
case 'i':
|
|
5290
5304
|
return /^\(?i[).]?$/;
|
|
@@ -5298,27 +5312,38 @@ function initial(type) {
|
|
|
5298
5312
|
return /^\(?[01][).]?$/;
|
|
5299
5313
|
}
|
|
5300
5314
|
}
|
|
5301
|
-
function format(
|
|
5302
|
-
if (
|
|
5303
|
-
|
|
5315
|
+
function format(list, type, form) {
|
|
5316
|
+
if (list.firstElementChild?.firstElementChild?.classList.contains('checkbox')) {
|
|
5317
|
+
list.classList.add('checklist');
|
|
5304
5318
|
}
|
|
5305
|
-
(0, dom_1.define)(
|
|
5319
|
+
(0, dom_1.define)(list, {
|
|
5306
5320
|
type: type || undefined,
|
|
5307
5321
|
'data-format': form === '.' ? undefined : 'paren',
|
|
5308
5322
|
'data-type': style(type) || undefined
|
|
5309
5323
|
});
|
|
5310
|
-
const marker =
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5324
|
+
const marker = list.firstElementChild?.getAttribute('data-marker') ?? '';
|
|
5325
|
+
// TODO: CSSカウンターをattr(start)でリセットできるようになればstart値からのオートインクリメントに対応させる。
|
|
5326
|
+
const start = marker.match(pattern(type))?.[0] ?? '';
|
|
5327
|
+
for (let es = list.children, len = es.length, i = 0; i < len; ++i) {
|
|
5328
|
+
const item = es[i];
|
|
5329
|
+
switch (item.getAttribute('data-marker')) {
|
|
5330
|
+
case null:
|
|
5317
5331
|
continue;
|
|
5332
|
+
case start:
|
|
5333
|
+
item.removeAttribute('data-marker');
|
|
5334
|
+
continue;
|
|
5335
|
+
case marker:
|
|
5336
|
+
if (i === 0 || item.classList.contains('invalid')) continue;
|
|
5337
|
+
(0, dom_1.define)(item, {
|
|
5338
|
+
class: 'invalid',
|
|
5339
|
+
'data-invalid-syntax': 'list',
|
|
5340
|
+
'data-invalid-type': 'index',
|
|
5341
|
+
'data-invalid-message': 'Fix the duplicate index'
|
|
5342
|
+
});
|
|
5318
5343
|
}
|
|
5319
5344
|
break;
|
|
5320
5345
|
}
|
|
5321
|
-
return
|
|
5346
|
+
return list;
|
|
5322
5347
|
}
|
|
5323
5348
|
|
|
5324
5349
|
/***/ }),
|
|
@@ -5587,11 +5612,11 @@ function fillFirstLine(ns) {
|
|
|
5587
5612
|
return ns.length === 1 && typeof ns[0] === 'object' && ['UL', 'OL'].includes(ns[0].tagName) ? (0, array_1.unshift)([(0, dom_1.html)('br')], ns) : ns;
|
|
5588
5613
|
}
|
|
5589
5614
|
exports.fillFirstLine = fillFirstLine;
|
|
5590
|
-
function format(
|
|
5591
|
-
if (
|
|
5592
|
-
|
|
5615
|
+
function format(list) {
|
|
5616
|
+
if (list.firstElementChild?.firstElementChild?.classList.contains('checkbox')) {
|
|
5617
|
+
list.classList.add('checklist');
|
|
5593
5618
|
}
|
|
5594
|
-
return
|
|
5619
|
+
return list;
|
|
5595
5620
|
}
|
|
5596
5621
|
|
|
5597
5622
|
/***/ }),
|
|
@@ -6118,16 +6143,18 @@ function identity(id, text, name = 'index') {
|
|
|
6118
6143
|
if (id === '') return undefined;
|
|
6119
6144
|
text &&= text.trim().replace(/\s+/g, '_');
|
|
6120
6145
|
if (text === '') return undefined;
|
|
6121
|
-
|
|
6146
|
+
const cs = [...text];
|
|
6147
|
+
if (cs.length <= 100) return `${name}:${id ?? ''}:${text}`;
|
|
6122
6148
|
switch (name) {
|
|
6123
6149
|
case 'index':
|
|
6124
|
-
return `${name}:${id ?? ''}:${
|
|
6150
|
+
return `${name}:${id ?? ''}:${cs.slice(0, 97).join('')}...`;
|
|
6125
6151
|
case 'mark':
|
|
6126
|
-
return `${name}:${id ?? ''}:${
|
|
6152
|
+
return `${name}:${id ?? ''}:${cs.slice(0, 50).join('')}...${cs.slice(-47).join('')}`;
|
|
6127
6153
|
}
|
|
6128
6154
|
}
|
|
6129
6155
|
exports.identity = identity;
|
|
6130
6156
|
function text(source, optional = false) {
|
|
6157
|
+
if (!source.firstChild) return '';
|
|
6131
6158
|
const indexer = source.querySelector(':scope > .indexer');
|
|
6132
6159
|
const index = indexer?.getAttribute('data-index');
|
|
6133
6160
|
if (index) return index;
|
|
@@ -6959,8 +6986,7 @@ function* figure(target, footnotes, opts = {}) {
|
|
|
6959
6986
|
}
|
|
6960
6987
|
labels.add(label);
|
|
6961
6988
|
opts.id !== '' && def.setAttribute('id', `label:${opts.id ? `${opts.id}:` : ''}${label}`);
|
|
6962
|
-
for (
|
|
6963
|
-
const ref = rs[i];
|
|
6989
|
+
for (const ref of refs.take(label, Infinity)) {
|
|
6964
6990
|
if (ref.getAttribute('data-invalid-message') === messages.reference) {
|
|
6965
6991
|
(0, dom_1.define)(ref, {
|
|
6966
6992
|
class: void ref.classList.remove('invalid'),
|
|
@@ -7026,7 +7052,6 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
7026
7052
|
}));
|
|
7027
7053
|
exports.reference = exports.annotation = exports.footnote = void 0;
|
|
7028
7054
|
const indexee_1 = __webpack_require__(1269);
|
|
7029
|
-
const queue_1 = __webpack_require__(4934);
|
|
7030
7055
|
const dom_1 = __webpack_require__(3252);
|
|
7031
7056
|
function* footnote(target, footnotes, opts = {}, bottom = null) {
|
|
7032
7057
|
for (let es = target.querySelectorAll(`.annotations`), len = es.length, i = 0; i < len; ++i) {
|
|
@@ -7040,23 +7065,35 @@ function* footnote(target, footnotes, opts = {}, bottom = null) {
|
|
|
7040
7065
|
exports.footnote = footnote;
|
|
7041
7066
|
exports.annotation = build('annotation', n => `*${n}`, 'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
7042
7067
|
exports.reference = build('reference', (n, abbr) => `[${abbr || n}]`);
|
|
7043
|
-
function build(syntax, marker, splitter) {
|
|
7068
|
+
function build(syntax, marker, splitter = '_') {
|
|
7044
7069
|
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
7045
7070
|
// 構文ごとに各1回の処理では不可能
|
|
7046
7071
|
return function* (target, footnote, opts = {}, bottom = null) {
|
|
7047
7072
|
const defs = new Map();
|
|
7048
|
-
const buffer = new queue_1.MultiQueue();
|
|
7049
|
-
const titles = new Map();
|
|
7050
7073
|
const splitters = [];
|
|
7051
|
-
for (let es = target.querySelectorAll(splitter
|
|
7074
|
+
for (let es = target.querySelectorAll(splitter), len = es.length, i = 0; i < len; ++i) {
|
|
7075
|
+
if (i % 100 === 0) yield;
|
|
7052
7076
|
const el = es[i];
|
|
7053
7077
|
el.parentNode === target && splitters.push(el);
|
|
7054
7078
|
}
|
|
7079
|
+
const refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`);
|
|
7080
|
+
const titles = new Map();
|
|
7081
|
+
const contents = new Map();
|
|
7082
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
7083
|
+
if (i % 10 === 9) yield;
|
|
7084
|
+
const ref = refs[i];
|
|
7085
|
+
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild.innerHTML}`;
|
|
7086
|
+
if (titles.has(identifier)) continue;
|
|
7087
|
+
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7088
|
+
const title = (0, indexee_1.text)(content).trim();
|
|
7089
|
+
if (!title) continue;
|
|
7090
|
+
titles.set(identifier, title);
|
|
7091
|
+
contents.set(identifier, content);
|
|
7092
|
+
}
|
|
7055
7093
|
let count = 0;
|
|
7056
7094
|
let total = 0;
|
|
7057
7095
|
let style;
|
|
7058
|
-
for (let
|
|
7059
|
-
yield;
|
|
7096
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
7060
7097
|
const ref = refs[i];
|
|
7061
7098
|
while (splitters.length > 0 && splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
7062
7099
|
if (defs.size > 0) {
|
|
@@ -7071,7 +7108,6 @@ function build(syntax, marker, splitter) {
|
|
|
7071
7108
|
}
|
|
7072
7109
|
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild.innerHTML}`;
|
|
7073
7110
|
const abbr = ref.getAttribute('data-abbr') || undefined;
|
|
7074
|
-
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7075
7111
|
style ??= abbr ? 'abbr' : 'count';
|
|
7076
7112
|
if (style === 'count' ? abbr : !abbr) {
|
|
7077
7113
|
(0, dom_1.define)(ref, {
|
|
@@ -7093,29 +7129,14 @@ function build(syntax, marker, splitter) {
|
|
|
7093
7129
|
} else {
|
|
7094
7130
|
ref.lastChild?.remove();
|
|
7095
7131
|
}
|
|
7096
|
-
const title = titles.get(identifier)
|
|
7097
|
-
|
|
7098
|
-
const blank = !!abbr && !content.firstChild;
|
|
7132
|
+
const title = titles.get(identifier);
|
|
7133
|
+
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7099
7134
|
const refIndex = ++count;
|
|
7100
7135
|
const refId = opts.id !== '' ? `${syntax}:${opts.id ?? ''}:ref:${refIndex}` : undefined;
|
|
7101
7136
|
const def = false || defs.get(identifier) || defs.set(identifier, (0, dom_1.html)('li', {
|
|
7102
7137
|
id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${total + defs.size + 1}` : undefined,
|
|
7103
7138
|
'data-marker': !footnote ? marker(total + defs.size + 1, abbr) : undefined
|
|
7104
|
-
}, [
|
|
7105
|
-
if (title && !blank && def.childNodes.length === 1) {
|
|
7106
|
-
def.insertBefore(content.cloneNode(true), def.lastChild);
|
|
7107
|
-
for (let refs = buffer.take(identifier, Infinity), i = 0; i < refs.length; ++i) {
|
|
7108
|
-
const ref = refs[i];
|
|
7109
|
-
if (ref.getAttribute('data-invalid-type') !== 'content') continue;
|
|
7110
|
-
(0, dom_1.define)(ref, {
|
|
7111
|
-
title,
|
|
7112
|
-
class: void ref.classList.remove('invalid'),
|
|
7113
|
-
'data-invalid-syntax': null,
|
|
7114
|
-
'data-invalid-type': null,
|
|
7115
|
-
'data-invalid-message': null
|
|
7116
|
-
});
|
|
7117
|
-
}
|
|
7118
|
-
}
|
|
7139
|
+
}, [contents.get(identifier) ?? (0, dom_1.frag)(), (0, dom_1.html)('sup')])).get(identifier);
|
|
7119
7140
|
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || total + defs.size;
|
|
7120
7141
|
const defId = def.id || undefined;
|
|
7121
7142
|
(0, dom_1.define)(ref, {
|
|
@@ -7135,7 +7156,7 @@ function build(syntax, marker, splitter) {
|
|
|
7135
7156
|
}, marker(defIndex, abbr)));
|
|
7136
7157
|
def.lastChild.appendChild((0, dom_1.html)('a', {
|
|
7137
7158
|
href: refId && `#${refId}`,
|
|
7138
|
-
title: abbr &&
|
|
7159
|
+
title: abbr && (0, indexee_1.text)(content).trim() || undefined
|
|
7139
7160
|
}, `^${refIndex}`));
|
|
7140
7161
|
}
|
|
7141
7162
|
if (defs.size > 0 || footnote) {
|
|
@@ -8368,7 +8389,7 @@ function unlink(h) {
|
|
|
8368
8389
|
/***/ 3252:
|
|
8369
8390
|
/***/ (function(module) {
|
|
8370
8391
|
|
|
8371
|
-
/*! typed-dom v0.0.
|
|
8392
|
+
/*! typed-dom v0.0.317 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */
|
|
8372
8393
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8373
8394
|
if(true)
|
|
8374
8395
|
module.exports = factory();
|
|
@@ -8699,7 +8720,7 @@ exports.defrag = defrag;
|
|
|
8699
8720
|
/***/ 6120:
|
|
8700
8721
|
/***/ (function(module) {
|
|
8701
8722
|
|
|
8702
|
-
/*! typed-dom v0.0.
|
|
8723
|
+
/*! typed-dom v0.0.317 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */
|
|
8703
8724
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8704
8725
|
if(true)
|
|
8705
8726
|
module.exports = factory();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.268.
|
|
3
|
+
"version": "0.268.2",
|
|
4
4
|
"description": "Secure markdown renderer working on browsers for user input data.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/falsandtru/securemark",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"@types/mocha": "10.0.1",
|
|
35
35
|
"@types/power-assert": "1.5.8",
|
|
36
36
|
"@types/prismjs": "1.26.0",
|
|
37
|
-
"@typescript-eslint/parser": "^5.
|
|
37
|
+
"@typescript-eslint/parser": "^5.54.0",
|
|
38
38
|
"babel-loader": "^9.1.2",
|
|
39
39
|
"babel-plugin-unassert": "^3.2.0",
|
|
40
40
|
"concurrently": "^7.6.0",
|
|
41
|
-
"eslint": "^8.
|
|
41
|
+
"eslint": "^8.35.0",
|
|
42
42
|
"eslint-plugin-redos": "^4.4.5",
|
|
43
43
|
"eslint-webpack-plugin": "^4.0.0",
|
|
44
44
|
"glob": "^8.1.0",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"karma-mocha": "^2.0.1",
|
|
50
50
|
"karma-power-assert": "^1.0.0",
|
|
51
51
|
"mocha": "^10.2.0",
|
|
52
|
-
"npm-check-updates": "^16.7.
|
|
52
|
+
"npm-check-updates": "^16.7.10",
|
|
53
53
|
"semver": "^7.3.8",
|
|
54
54
|
"spica": "0.0.719",
|
|
55
55
|
"ts-loader": "^9.4.2",
|
|
56
|
-
"typed-dom": "^0.0.
|
|
56
|
+
"typed-dom": "^0.0.317",
|
|
57
57
|
"typescript": "4.9.5",
|
|
58
58
|
"webpack": "^5.75.0",
|
|
59
59
|
"webpack-cli": "^5.0.1",
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { autolink } from './autolink';
|
|
2
|
-
import { some } from '../combinator';
|
|
3
2
|
import { inspect } from '../debug.test';
|
|
4
3
|
|
|
5
4
|
describe('Unit: parser/autolink', () => {
|
|
6
5
|
describe('autolink', () => {
|
|
7
|
-
const parser = (source: string) =>
|
|
6
|
+
const parser = (source: string) => autolink({ source, context: {} });
|
|
8
7
|
|
|
9
8
|
it('basic', () => {
|
|
10
9
|
assert.deepStrictEqual(inspect(parser(' http://host')), [[' ', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
@@ -30,7 +30,7 @@ describe('Unit: parser/block/olist', () => {
|
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('(1)\n')), undefined);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('(I) ')), undefined);
|
|
32
32
|
assert.deepStrictEqual(inspect(parser('(A) ')), undefined);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser(' 1.')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser(' 1. ')), undefined);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it('single', () => {
|
|
@@ -91,7 +91,7 @@ describe('Unit: parser/block/olist', () => {
|
|
|
91
91
|
assert.deepStrictEqual(inspect(parser('01. ')), [['<ol><li data-marker="01."></li></ol>'], '']);
|
|
92
92
|
assert.deepStrictEqual(inspect(parser('0.\n1')), [['<ol><li></li><li data-marker="1."></li></ol>'], '']);
|
|
93
93
|
assert.deepStrictEqual(inspect(parser('8.\n9')), [['<ol><li data-marker="8."></li><li data-marker="9."></li></ol>'], '']);
|
|
94
|
-
assert.deepStrictEqual(inspect(parser('9.\n9')), [['<ol><li data-marker="9."></li><li data-marker="9."></li></ol>'], '']);
|
|
94
|
+
assert.deepStrictEqual(inspect(parser('9.\n9')), [['<ol><li data-marker="9."></li><li data-marker="9." class="invalid"></li></ol>'], '']);
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('branch', () => {
|
|
@@ -27,10 +27,10 @@ export const olist: OListParser = lazy(() => block(validate(
|
|
|
27
27
|
export const olist_: OListParser = lazy(() => block(union([
|
|
28
28
|
match(
|
|
29
29
|
openers['.'],
|
|
30
|
-
memoize(ms => list(type(ms[1]), '.'), ms =>
|
|
30
|
+
memoize(ms => list(type(ms[1]), '.'), ms => index(ms[1]), [])),
|
|
31
31
|
match(
|
|
32
32
|
openers['('],
|
|
33
|
-
memoize(ms => list(type(ms[1]), '('), ms =>
|
|
33
|
+
memoize(ms => list(type(ms[1]), '('), ms => index(ms[1]), [])),
|
|
34
34
|
])));
|
|
35
35
|
|
|
36
36
|
const list = (type: string, form: string): OListParser.ListParser => fmap(
|
|
@@ -61,14 +61,29 @@ export const invalid = rewrite(
|
|
|
61
61
|
'',
|
|
62
62
|
html('span', {
|
|
63
63
|
class: 'invalid',
|
|
64
|
-
'data-invalid-syntax': '
|
|
64
|
+
'data-invalid-syntax': 'list',
|
|
65
65
|
'data-invalid-type': 'syntax',
|
|
66
66
|
'data-invalid-message': 'Fix the indent or the head of the list item',
|
|
67
67
|
}, source.replace('\n', ''))
|
|
68
68
|
], '']);
|
|
69
69
|
|
|
70
|
-
function
|
|
71
|
-
switch (
|
|
70
|
+
function index(value: string): number {
|
|
71
|
+
switch (value) {
|
|
72
|
+
case 'i':
|
|
73
|
+
return 1;
|
|
74
|
+
case 'a':
|
|
75
|
+
return 2;
|
|
76
|
+
case 'I':
|
|
77
|
+
return 3;
|
|
78
|
+
case 'A':
|
|
79
|
+
return 4;
|
|
80
|
+
default:
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function type(value: string): string {
|
|
86
|
+
switch (value) {
|
|
72
87
|
case 'i':
|
|
73
88
|
return 'i';
|
|
74
89
|
case 'a':
|
|
@@ -97,7 +112,7 @@ function style(type: string): string {
|
|
|
97
112
|
}
|
|
98
113
|
}
|
|
99
114
|
|
|
100
|
-
function
|
|
115
|
+
function pattern(type: string): RegExp {
|
|
101
116
|
switch (type) {
|
|
102
117
|
case 'i':
|
|
103
118
|
return /^\(?i[).]?$/;
|
|
@@ -112,25 +127,37 @@ function initial(type: string): RegExp {
|
|
|
112
127
|
}
|
|
113
128
|
}
|
|
114
129
|
|
|
115
|
-
function format(
|
|
116
|
-
if (
|
|
117
|
-
|
|
130
|
+
function format(list: HTMLOListElement, type: string, form: string): HTMLOListElement {
|
|
131
|
+
if (list.firstElementChild?.firstElementChild?.classList.contains('checkbox')) {
|
|
132
|
+
list.classList.add('checklist');
|
|
118
133
|
}
|
|
119
|
-
define(
|
|
134
|
+
define(list, {
|
|
120
135
|
type: type || undefined,
|
|
121
136
|
'data-format': form === '.' ? undefined : 'paren',
|
|
122
137
|
'data-type': style(type) || undefined,
|
|
123
138
|
});
|
|
124
|
-
const marker =
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
const marker = list.firstElementChild?.getAttribute('data-marker') ?? '';
|
|
140
|
+
// TODO: CSSカウンターをattr(start)でリセットできるようになればstart値からのオートインクリメントに対応させる。
|
|
141
|
+
const start = marker.match(pattern(type))?.[0] ?? '';
|
|
142
|
+
for (let es = list.children, len = es.length, i = 0; i < len; ++i) {
|
|
143
|
+
const item = es[i];
|
|
144
|
+
assert(item.getAttribute('data-marker') !== '');
|
|
145
|
+
switch (item.getAttribute('data-marker')) {
|
|
146
|
+
case null:
|
|
131
147
|
continue;
|
|
148
|
+
case start:
|
|
149
|
+
item.removeAttribute('data-marker');
|
|
150
|
+
continue;
|
|
151
|
+
case marker:
|
|
152
|
+
if (i === 0 || item.classList.contains('invalid')) continue;
|
|
153
|
+
define(item, {
|
|
154
|
+
class: 'invalid',
|
|
155
|
+
'data-invalid-syntax': 'list',
|
|
156
|
+
'data-invalid-type': 'index',
|
|
157
|
+
'data-invalid-message': 'Fix the duplicate index',
|
|
158
|
+
});
|
|
132
159
|
}
|
|
133
160
|
break;
|
|
134
161
|
}
|
|
135
|
-
return
|
|
162
|
+
return list;
|
|
136
163
|
}
|
|
@@ -17,7 +17,7 @@ describe('Unit: parser/block/ulist', () => {
|
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('-[ ]')), undefined);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('-[x]')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('-\n')), undefined);
|
|
20
|
-
assert.deepStrictEqual(inspect(parser(' -')), undefined);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser(' - ')), undefined);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('+')), undefined);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('*')), undefined);
|
|
23
23
|
});
|
|
@@ -40,9 +40,9 @@ export function fillFirstLine(ns: (HTMLElement | string)[]): (HTMLElement | stri
|
|
|
40
40
|
: ns;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function format(
|
|
44
|
-
if (
|
|
45
|
-
|
|
43
|
+
function format(list: HTMLUListElement): HTMLUListElement {
|
|
44
|
+
if (list.firstElementChild?.firstElementChild?.classList.contains('checkbox')) {
|
|
45
|
+
list.classList.add('checklist');
|
|
46
46
|
}
|
|
47
|
-
return
|
|
47
|
+
return list;
|
|
48
48
|
}
|
|
@@ -14,12 +14,13 @@ export function identity(id: string | undefined, text: string, name: 'index' | '
|
|
|
14
14
|
if (id === '') return undefined;
|
|
15
15
|
text &&= text.trim().replace(/\s+/g, '_');
|
|
16
16
|
if (text === '') return undefined;
|
|
17
|
-
|
|
17
|
+
const cs = [...text];
|
|
18
|
+
if (cs.length <= 100) return `${name}:${id ?? ''}:${text}`;
|
|
18
19
|
switch (name) {
|
|
19
20
|
case 'index':
|
|
20
|
-
return `${name}:${id ?? ''}:${
|
|
21
|
+
return `${name}:${id ?? ''}:${cs.slice(0, 97).join('')}...`;
|
|
21
22
|
case 'mark':
|
|
22
|
-
return `${name}:${id ?? ''}:${
|
|
23
|
+
return `${name}:${id ?? ''}:${cs.slice(0, 50).join('')}...${cs.slice(-47).join('')}`;
|
|
23
24
|
}
|
|
24
25
|
assert(false);
|
|
25
26
|
}
|
|
@@ -33,6 +34,7 @@ assert(identity(undefined, '0'.repeat(200) + 1, 'mark')!.slice(6) === '0'.repeat
|
|
|
33
34
|
export function text(source: HTMLElement | DocumentFragment, optional = false): string {
|
|
34
35
|
assert(source instanceof DocumentFragment || !source.matches('.indexer'));
|
|
35
36
|
assert(source.querySelectorAll(':scope > .indexer').length <= 1);
|
|
37
|
+
if (!source.firstChild) return '';
|
|
36
38
|
const indexer = source.querySelector(':scope > .indexer');
|
|
37
39
|
const index = indexer?.getAttribute('data-index');
|
|
38
40
|
if (index) return index;
|
|
@@ -139,8 +139,7 @@ export function* figure(
|
|
|
139
139
|
}
|
|
140
140
|
labels.add(label);
|
|
141
141
|
opts.id !== '' && def.setAttribute('id', `label:${opts.id ? `${opts.id}:` : ''}${label}`);
|
|
142
|
-
for (
|
|
143
|
-
const ref = rs[i];
|
|
142
|
+
for (const ref of refs.take(label, Infinity)) {
|
|
144
143
|
if (ref.getAttribute('data-invalid-message') === messages.reference) {
|
|
145
144
|
define(ref, {
|
|
146
145
|
class: void ref.classList.remove('invalid'),
|
|
@@ -22,7 +22,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
22
22
|
const target = parse('((a b))');
|
|
23
23
|
const footnote = html('ol');
|
|
24
24
|
for (let i = 0; i < 3; ++i) {
|
|
25
|
-
assert.deepStrictEqual([...annotation(target, footnote)].length, i === 0 ?
|
|
25
|
+
assert.deepStrictEqual([...annotation(target, footnote)].length, i === 0 ? 2 : 1);
|
|
26
26
|
assert.deepStrictEqual(
|
|
27
27
|
[...target.children].map(el => el.outerHTML),
|
|
28
28
|
[
|
|
@@ -48,7 +48,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
48
48
|
const target = parse('((1))((12345678901234567890))');
|
|
49
49
|
const footnote = html('ol');
|
|
50
50
|
for (let i = 0; i < 3; ++i) {
|
|
51
|
-
assert.deepStrictEqual([...annotation(target, footnote)].length, i === 0 ?
|
|
51
|
+
assert.deepStrictEqual([...annotation(target, footnote)].length, i === 0 ? 4 : 2);
|
|
52
52
|
assert.deepStrictEqual(
|
|
53
53
|
[...target.children].map(el => el.outerHTML),
|
|
54
54
|
[
|
|
@@ -165,7 +165,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
165
165
|
const target = parse('((a b))');
|
|
166
166
|
const footnote = html('ol');
|
|
167
167
|
for (let i = 0; i < 3; ++i) {
|
|
168
|
-
assert.deepStrictEqual([...annotation(target, footnote, { id: '0' })].length, i === 0 ?
|
|
168
|
+
assert.deepStrictEqual([...annotation(target, footnote, { id: '0' })].length, i === 0 ? 2 : 1);
|
|
169
169
|
assert.deepStrictEqual(
|
|
170
170
|
[...target.children].map(el => el.outerHTML),
|
|
171
171
|
[
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { text } from '../inline/extension/indexee';
|
|
2
|
-
import { MultiQueue } from 'spica/queue';
|
|
3
2
|
import { frag, html, define } from 'typed-dom/dom';
|
|
4
3
|
|
|
5
4
|
export function* footnote(
|
|
@@ -24,7 +23,7 @@ export const reference = build('reference', (n, abbr) => `[${abbr || n}]`);
|
|
|
24
23
|
function build(
|
|
25
24
|
syntax: 'annotation' | 'reference',
|
|
26
25
|
marker: (index: number, abbr: string | undefined) => string,
|
|
27
|
-
splitter
|
|
26
|
+
splitter: string = '_',
|
|
28
27
|
) {
|
|
29
28
|
assert(syntax.match(/^[a-z]+$/));
|
|
30
29
|
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
@@ -36,21 +35,31 @@ function build(
|
|
|
36
35
|
bottom: Node | null = null,
|
|
37
36
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
38
37
|
const defs = new Map<string, HTMLLIElement>();
|
|
39
|
-
const buffer = new MultiQueue<string, HTMLElement>();
|
|
40
|
-
const titles = new Map<string, string>();
|
|
41
38
|
const splitters: Element[] = [];
|
|
42
|
-
for (let es = target.querySelectorAll(splitter
|
|
39
|
+
for (let es = target.querySelectorAll(splitter),
|
|
43
40
|
len = es.length, i = 0; i < len; ++i) {
|
|
41
|
+
if (i % 100 === 0) yield;
|
|
44
42
|
const el = es[i];
|
|
45
43
|
el.parentNode === target && splitters.push(el);
|
|
46
44
|
}
|
|
45
|
+
const refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`);
|
|
46
|
+
const titles = new Map<string, string>();
|
|
47
|
+
const contents = new Map<string, DocumentFragment>();
|
|
48
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
49
|
+
if (i % 10 === 9) yield;
|
|
50
|
+
const ref = refs[i];
|
|
51
|
+
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild!.innerHTML}`;
|
|
52
|
+
if (titles.has(identifier)) continue;
|
|
53
|
+
const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
|
|
54
|
+
const title = text(content).trim();
|
|
55
|
+
if (!title) continue;
|
|
56
|
+
titles.set(identifier, title);
|
|
57
|
+
contents.set(identifier, content);
|
|
58
|
+
}
|
|
47
59
|
let count = 0;
|
|
48
60
|
let total = 0;
|
|
49
61
|
let style: 'count' | 'abbr';
|
|
50
|
-
for (
|
|
51
|
-
let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`),
|
|
52
|
-
len = refs.length, i = 0; i < len; ++i) {
|
|
53
|
-
yield;
|
|
62
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
54
63
|
const ref = refs[i];
|
|
55
64
|
while (splitters.length > 0
|
|
56
65
|
&& splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
@@ -65,7 +74,6 @@ function build(
|
|
|
65
74
|
}
|
|
66
75
|
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild!.innerHTML}`;
|
|
67
76
|
const abbr = ref.getAttribute('data-abbr') || undefined;
|
|
68
|
-
const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
|
|
69
77
|
style ??= abbr ? 'abbr' : 'count';
|
|
70
78
|
if (style === 'count' ? abbr : !abbr) {
|
|
71
79
|
define(ref, {
|
|
@@ -89,14 +97,10 @@ function build(
|
|
|
89
97
|
else {
|
|
90
98
|
ref.lastChild?.remove();
|
|
91
99
|
}
|
|
92
|
-
const title = titles.get(identifier)
|
|
100
|
+
const title = titles.get(identifier);
|
|
93
101
|
assert(title !== '');
|
|
94
102
|
assert(syntax !== 'annotation' || title);
|
|
95
|
-
|
|
96
|
-
? !titles.has(identifier) && titles.set(identifier, title)
|
|
97
|
-
: buffer.set(identifier, ref);
|
|
98
|
-
assert(syntax !== 'annotation' || !buffer.has(identifier));
|
|
99
|
-
const blank = !!abbr && !content.firstChild;
|
|
103
|
+
const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
|
|
100
104
|
const refIndex = ++count;
|
|
101
105
|
const refId = opts.id !== ''
|
|
102
106
|
? `${syntax}:${opts.id ?? ''}:ref:${refIndex}`
|
|
@@ -108,24 +112,9 @@ function build(
|
|
|
108
112
|
id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${total + defs.size + 1}` : undefined,
|
|
109
113
|
'data-marker': !footnote ? marker(total + defs.size + 1, abbr) : undefined,
|
|
110
114
|
},
|
|
111
|
-
[
|
|
115
|
+
[contents.get(identifier) ?? frag(), html('sup')]))
|
|
112
116
|
.get(identifier)!;
|
|
113
117
|
assert(def.lastChild);
|
|
114
|
-
if (title && !blank && def.childNodes.length === 1) {
|
|
115
|
-
def.insertBefore(content.cloneNode(true), def.lastChild);
|
|
116
|
-
assert(def.childNodes.length > 1);
|
|
117
|
-
for (let refs = buffer.take(identifier, Infinity), i = 0; i < refs.length; ++i) {
|
|
118
|
-
const ref = refs[i];
|
|
119
|
-
if (ref.getAttribute('data-invalid-type') !== 'content') continue;
|
|
120
|
-
define(ref, {
|
|
121
|
-
title,
|
|
122
|
-
class: void ref.classList.remove('invalid'),
|
|
123
|
-
'data-invalid-syntax': null,
|
|
124
|
-
'data-invalid-type': null,
|
|
125
|
-
'data-invalid-message': null,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
118
|
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || total + defs.size;
|
|
130
119
|
const defId = def.id || undefined;
|
|
131
120
|
define(ref, {
|
|
@@ -145,9 +134,7 @@ function build(
|
|
|
145
134
|
html('a',
|
|
146
135
|
{
|
|
147
136
|
href: refId && `#${refId}`,
|
|
148
|
-
title: abbr &&
|
|
149
|
-
? title
|
|
150
|
-
: undefined,
|
|
137
|
+
title: abbr && text(content).trim() || undefined,
|
|
151
138
|
},
|
|
152
139
|
`^${refIndex}`));
|
|
153
140
|
}
|
package/src/util/info.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ParseSelector } from 'typed-query-selector/parser';
|
|
1
2
|
import { Info } from '../..';
|
|
2
3
|
import { scope } from './scope';
|
|
3
4
|
|
|
@@ -16,9 +17,10 @@ export function info(source: DocumentFragment | HTMLElement | ShadowRoot): Info
|
|
|
16
17
|
media: find('.media[data-src]'),
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
function find<T extends
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
function find<T extends string>(selector: T): ParseSelector<T, HTMLElement>[];
|
|
21
|
+
function find(selector: string): HTMLElement[] {
|
|
22
|
+
const acc = [];
|
|
23
|
+
for (let es = source.querySelectorAll<HTMLElement>(selector),
|
|
22
24
|
len = es.length, i = 0; i < len; ++i) {
|
|
23
25
|
const el = es[i];
|
|
24
26
|
match(el) && acc.push(el);
|