securemark 0.268.0 → 0.268.1
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 +4 -0
- package/README.md +0 -4
- package/dist/index.js +73 -53
- 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 +1 -0
- 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/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.268.
|
|
1
|
+
/*! securemark v0.268.1 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
|
/***/ }),
|
|
@@ -6128,6 +6153,7 @@ function identity(id, text, name = 'index') {
|
|
|
6128
6153
|
}
|
|
6129
6154
|
exports.identity = identity;
|
|
6130
6155
|
function text(source, optional = false) {
|
|
6156
|
+
if (!source.firstChild) return '';
|
|
6131
6157
|
const indexer = source.querySelector(':scope > .indexer');
|
|
6132
6158
|
const index = indexer?.getAttribute('data-index');
|
|
6133
6159
|
if (index) return index;
|
|
@@ -6959,8 +6985,7 @@ function* figure(target, footnotes, opts = {}) {
|
|
|
6959
6985
|
}
|
|
6960
6986
|
labels.add(label);
|
|
6961
6987
|
opts.id !== '' && def.setAttribute('id', `label:${opts.id ? `${opts.id}:` : ''}${label}`);
|
|
6962
|
-
for (
|
|
6963
|
-
const ref = rs[i];
|
|
6988
|
+
for (const ref of refs.take(label, Infinity)) {
|
|
6964
6989
|
if (ref.getAttribute('data-invalid-message') === messages.reference) {
|
|
6965
6990
|
(0, dom_1.define)(ref, {
|
|
6966
6991
|
class: void ref.classList.remove('invalid'),
|
|
@@ -7026,7 +7051,6 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
7026
7051
|
}));
|
|
7027
7052
|
exports.reference = exports.annotation = exports.footnote = void 0;
|
|
7028
7053
|
const indexee_1 = __webpack_require__(1269);
|
|
7029
|
-
const queue_1 = __webpack_require__(4934);
|
|
7030
7054
|
const dom_1 = __webpack_require__(3252);
|
|
7031
7055
|
function* footnote(target, footnotes, opts = {}, bottom = null) {
|
|
7032
7056
|
for (let es = target.querySelectorAll(`.annotations`), len = es.length, i = 0; i < len; ++i) {
|
|
@@ -7040,23 +7064,35 @@ function* footnote(target, footnotes, opts = {}, bottom = null) {
|
|
|
7040
7064
|
exports.footnote = footnote;
|
|
7041
7065
|
exports.annotation = build('annotation', n => `*${n}`, 'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
7042
7066
|
exports.reference = build('reference', (n, abbr) => `[${abbr || n}]`);
|
|
7043
|
-
function build(syntax, marker, splitter) {
|
|
7067
|
+
function build(syntax, marker, splitter = '_') {
|
|
7044
7068
|
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
7045
7069
|
// 構文ごとに各1回の処理では不可能
|
|
7046
7070
|
return function* (target, footnote, opts = {}, bottom = null) {
|
|
7047
7071
|
const defs = new Map();
|
|
7048
|
-
const buffer = new queue_1.MultiQueue();
|
|
7049
|
-
const titles = new Map();
|
|
7050
7072
|
const splitters = [];
|
|
7051
|
-
for (let es = target.querySelectorAll(splitter
|
|
7073
|
+
for (let es = target.querySelectorAll(splitter), len = es.length, i = 0; i < len; ++i) {
|
|
7074
|
+
if (i % 100 === 0) yield;
|
|
7052
7075
|
const el = es[i];
|
|
7053
7076
|
el.parentNode === target && splitters.push(el);
|
|
7054
7077
|
}
|
|
7078
|
+
const refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`);
|
|
7079
|
+
const titles = new Map();
|
|
7080
|
+
const contents = new Map();
|
|
7081
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
7082
|
+
if (i % 10 === 9) yield;
|
|
7083
|
+
const ref = refs[i];
|
|
7084
|
+
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild.innerHTML}`;
|
|
7085
|
+
if (titles.has(identifier)) continue;
|
|
7086
|
+
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7087
|
+
const title = (0, indexee_1.text)(content).trim();
|
|
7088
|
+
if (!title) continue;
|
|
7089
|
+
titles.set(identifier, title);
|
|
7090
|
+
contents.set(identifier, content);
|
|
7091
|
+
}
|
|
7055
7092
|
let count = 0;
|
|
7056
7093
|
let total = 0;
|
|
7057
7094
|
let style;
|
|
7058
|
-
for (let
|
|
7059
|
-
yield;
|
|
7095
|
+
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
7060
7096
|
const ref = refs[i];
|
|
7061
7097
|
while (splitters.length > 0 && splitters[0].compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
7062
7098
|
if (defs.size > 0) {
|
|
@@ -7071,7 +7107,6 @@ function build(syntax, marker, splitter) {
|
|
|
7071
7107
|
}
|
|
7072
7108
|
const identifier = ref.getAttribute('data-abbr') || ` ${ref.firstElementChild.innerHTML}`;
|
|
7073
7109
|
const abbr = ref.getAttribute('data-abbr') || undefined;
|
|
7074
|
-
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7075
7110
|
style ??= abbr ? 'abbr' : 'count';
|
|
7076
7111
|
if (style === 'count' ? abbr : !abbr) {
|
|
7077
7112
|
(0, dom_1.define)(ref, {
|
|
@@ -7093,29 +7128,14 @@ function build(syntax, marker, splitter) {
|
|
|
7093
7128
|
} else {
|
|
7094
7129
|
ref.lastChild?.remove();
|
|
7095
7130
|
}
|
|
7096
|
-
const title = titles.get(identifier)
|
|
7097
|
-
|
|
7098
|
-
const blank = !!abbr && !content.firstChild;
|
|
7131
|
+
const title = titles.get(identifier);
|
|
7132
|
+
const content = (0, dom_1.frag)(ref.firstElementChild.cloneNode(true).childNodes);
|
|
7099
7133
|
const refIndex = ++count;
|
|
7100
7134
|
const refId = opts.id !== '' ? `${syntax}:${opts.id ?? ''}:ref:${refIndex}` : undefined;
|
|
7101
7135
|
const def = false || defs.get(identifier) || defs.set(identifier, (0, dom_1.html)('li', {
|
|
7102
7136
|
id: opts.id !== '' ? `${syntax}:${opts.id ?? ''}:def:${total + defs.size + 1}` : undefined,
|
|
7103
7137
|
'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
|
-
}
|
|
7138
|
+
}, [contents.get(identifier) ?? (0, dom_1.frag)(), (0, dom_1.html)('sup')])).get(identifier);
|
|
7119
7139
|
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || total + defs.size;
|
|
7120
7140
|
const defId = def.id || undefined;
|
|
7121
7141
|
(0, dom_1.define)(ref, {
|
|
@@ -7135,7 +7155,7 @@ function build(syntax, marker, splitter) {
|
|
|
7135
7155
|
}, marker(defIndex, abbr)));
|
|
7136
7156
|
def.lastChild.appendChild((0, dom_1.html)('a', {
|
|
7137
7157
|
href: refId && `#${refId}`,
|
|
7138
|
-
title: abbr &&
|
|
7158
|
+
title: abbr && (0, indexee_1.text)(content).trim() || undefined
|
|
7139
7159
|
}, `^${refIndex}`));
|
|
7140
7160
|
}
|
|
7141
7161
|
if (defs.size > 0 || footnote) {
|
|
@@ -8368,7 +8388,7 @@ function unlink(h) {
|
|
|
8368
8388
|
/***/ 3252:
|
|
8369
8389
|
/***/ (function(module) {
|
|
8370
8390
|
|
|
8371
|
-
/*! typed-dom v0.0.
|
|
8391
|
+
/*! typed-dom v0.0.316 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */
|
|
8372
8392
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8373
8393
|
if(true)
|
|
8374
8394
|
module.exports = factory();
|
|
@@ -8699,7 +8719,7 @@ exports.defrag = defrag;
|
|
|
8699
8719
|
/***/ 6120:
|
|
8700
8720
|
/***/ (function(module) {
|
|
8701
8721
|
|
|
8702
|
-
/*! typed-dom v0.0.
|
|
8722
|
+
/*! typed-dom v0.0.316 https://github.com/falsandtru/typed-dom | (c) 2016, falsandtru | (Apache-2.0 AND MPL-2.0) License */
|
|
8703
8723
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
8704
8724
|
if(true)
|
|
8705
8725
|
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.1",
|
|
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.53.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.9",
|
|
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.316",
|
|
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
|
}
|
|
@@ -33,6 +33,7 @@ assert(identity(undefined, '0'.repeat(200) + 1, 'mark')!.slice(6) === '0'.repeat
|
|
|
33
33
|
export function text(source: HTMLElement | DocumentFragment, optional = false): string {
|
|
34
34
|
assert(source instanceof DocumentFragment || !source.matches('.indexer'));
|
|
35
35
|
assert(source.querySelectorAll(':scope > .indexer').length <= 1);
|
|
36
|
+
if (!source.firstChild) return '';
|
|
36
37
|
const indexer = source.querySelector(':scope > .indexer');
|
|
37
38
|
const index = indexer?.getAttribute('data-index');
|
|
38
39
|
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
|
}
|