securemark 0.299.1 → 0.299.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 +4 -0
- package/dist/index.js +138 -42
- package/markdown.d.ts +2 -2
- package/package.json +1 -1
- package/src/combinator/data/delimiter.ts +2 -0
- package/src/combinator/data/parser/some.ts +13 -5
- package/src/parser/api/header.ts +5 -1
- package/src/parser/api/parse.test.ts +9 -9
- package/src/parser/context.ts +1 -1
- package/src/parser/header.test.ts +5 -5
- package/src/parser/header.ts +2 -3
- package/src/parser/inline/annotation.ts +8 -3
- package/src/parser/inline/autolink/url.ts +3 -4
- package/src/parser/inline/math.test.ts +2 -2
- package/src/parser/inline/math.ts +3 -3
- package/src/parser/inline/ruby.ts +2 -3
- package/src/parser/inline.test.ts +1 -1
- package/src/parser/repeat.ts +4 -4
- package/src/parser/source/escapable.ts +28 -5
- package/src/parser/source/text.ts +8 -16
- package/src/parser/source/unescapable.test.ts +1 -1
- package/src/parser/source/unescapable.ts +86 -5
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.299.
|
|
1
|
+
/*! securemark v0.299.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"));
|
|
@@ -3745,16 +3745,21 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
3745
3745
|
}));
|
|
3746
3746
|
exports.some = void 0;
|
|
3747
3747
|
const delimiter_1 = __webpack_require__(385);
|
|
3748
|
-
function some(parser, delimiter, after, delimiters, limit =
|
|
3748
|
+
function some(parser, delimiter, after, delimiters, limit = 0) {
|
|
3749
3749
|
if (typeof delimiter === 'number') {
|
|
3750
3750
|
limit = delimiter;
|
|
3751
|
+
delimiters = undefined;
|
|
3751
3752
|
delimiter = undefined;
|
|
3752
3753
|
} else if (Array.isArray(delimiter)) {
|
|
3754
|
+
limit = after;
|
|
3753
3755
|
delimiters = delimiter;
|
|
3754
3756
|
delimiter = undefined;
|
|
3755
3757
|
} else if (after === undefined || Array.isArray(after)) {
|
|
3758
|
+
limit = delimiters;
|
|
3756
3759
|
delimiters = after;
|
|
3757
3760
|
after = undefined;
|
|
3761
|
+
} else {
|
|
3762
|
+
delimiters = delimiters;
|
|
3758
3763
|
}
|
|
3759
3764
|
const match = delimiter_1.Delimiters.tester(delimiter, after);
|
|
3760
3765
|
const delims = delimiters?.map(([delimiter, precedence]) => ({
|
|
@@ -3780,7 +3785,8 @@ function some(parser, delimiter, after, delimiters, limit = -1) {
|
|
|
3780
3785
|
if (result === undefined) break;
|
|
3781
3786
|
if (context.position === pos) break;
|
|
3782
3787
|
nodes = nodes?.import(result) ?? result;
|
|
3783
|
-
|
|
3788
|
+
// 次にパースに成功すれば確実に制限値を超えるので制限値ちょうどでも中止する
|
|
3789
|
+
if (limit > 0 && context.position - position >= limit) break;
|
|
3784
3790
|
}
|
|
3785
3791
|
delims && context.delimiters.pop(delims.length);
|
|
3786
3792
|
return context.position > position ? nodes : undefined;
|
|
@@ -4201,7 +4207,11 @@ function header(source) {
|
|
|
4201
4207
|
exports.header = header;
|
|
4202
4208
|
function headers(source) {
|
|
4203
4209
|
const [el] = parse(source);
|
|
4204
|
-
|
|
4210
|
+
const acc = [];
|
|
4211
|
+
for (let field = el?.firstChild?.firstChild; field = field?.nextSibling;) {
|
|
4212
|
+
acc.push(field.textContent);
|
|
4213
|
+
}
|
|
4214
|
+
return acc;
|
|
4205
4215
|
}
|
|
4206
4216
|
exports.headers = headers;
|
|
4207
4217
|
function parse(source) {
|
|
@@ -5827,7 +5837,7 @@ class Context extends parser_1.Context {
|
|
|
5827
5837
|
} = options;
|
|
5828
5838
|
this.resources ??= {
|
|
5829
5839
|
// バックトラックのせいで文字数制限を受けないようにする。
|
|
5830
|
-
clock: exports.MAX_SEGMENT_SIZE * (
|
|
5840
|
+
clock: exports.MAX_SEGMENT_SIZE * (5 + 1),
|
|
5831
5841
|
recursions: [5 || 0 /* Recursion.block */, 20 || 0 /* Recursion.blockquote */, 40 || 0 /* Recursion.listitem */, 20 || 0 /* Recursion.inline */, 20 || 0 /* Recursion.bracket */, 20 || 0 /* Recursion.terminal */]
|
|
5832
5842
|
};
|
|
5833
5843
|
this.segment = segment ?? 0 /* Segment.unknown */;
|
|
@@ -5881,7 +5891,7 @@ const combinator_1 = __webpack_require__(3484);
|
|
|
5881
5891
|
const source_1 = __webpack_require__(8745);
|
|
5882
5892
|
const util_1 = __webpack_require__(4992);
|
|
5883
5893
|
const dom_1 = __webpack_require__(394);
|
|
5884
|
-
exports.header = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/---+[^\S\r\n]*\r?\n(?=\S)/y, (0, combinator_1.inits)([(0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.validate)(context => context.header, (0, combinator_1.focus)(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,
|
|
5894
|
+
exports.header = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/---+[^\S\r\n]*\r?\n(?=\S)/y, (0, combinator_1.inits)([(0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.validate)(context => context.header, (0, combinator_1.focus)(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi, (0, combinator_1.convert)(source => source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')), (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.union)([field])), ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('aside', {
|
|
5885
5895
|
class: 'header'
|
|
5886
5896
|
}, [(0, dom_1.html)('details', {
|
|
5887
5897
|
open: ''
|
|
@@ -5903,7 +5913,7 @@ const field = (0, combinator_1.line)(({
|
|
|
5903
5913
|
}) => {
|
|
5904
5914
|
const name = source.slice(position, source.indexOf(':', position));
|
|
5905
5915
|
const value = source.slice(position + name.length + 1).trim();
|
|
5906
|
-
return new parser_1.List([new parser_1.Node((0, dom_1.html)('
|
|
5916
|
+
return new parser_1.List([new parser_1.Node((0, dom_1.html)('div', {
|
|
5907
5917
|
class: 'field',
|
|
5908
5918
|
'data-name': name.toLowerCase(),
|
|
5909
5919
|
'data-value': value
|
|
@@ -5911,7 +5921,7 @@ const field = (0, combinator_1.line)(({
|
|
|
5911
5921
|
class: 'field-name'
|
|
5912
5922
|
}, name), ': ', (0, dom_1.html)('span', {
|
|
5913
5923
|
class: 'field-value'
|
|
5914
|
-
}, value)
|
|
5924
|
+
}, value)]))]);
|
|
5915
5925
|
});
|
|
5916
5926
|
|
|
5917
5927
|
/***/ },
|
|
@@ -6359,10 +6369,9 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
6359
6369
|
exports.lineurl = exports.url = void 0;
|
|
6360
6370
|
const parser_1 = __webpack_require__(605);
|
|
6361
6371
|
const combinator_1 = __webpack_require__(3484);
|
|
6362
|
-
const inline_1 = __webpack_require__(7973);
|
|
6363
6372
|
const link_1 = __webpack_require__(3628);
|
|
6364
6373
|
const source_1 = __webpack_require__(8745);
|
|
6365
|
-
exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[
|
|
6374
|
+
exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[[0-9A-Za-z])/y, (0, combinator_1.precedence)(0, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y), (0, combinator_1.precedence)(1, bracket)]), [[/[^\x21-\x7E]|\$/y, 9]])), false, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, context => new parser_1.List([new parser_1.Node((0, link_1.parse)(new parser_1.List(), new parser_1.List([new parser_1.Node(context.source)]), context))]))), context => new parser_1.List([new parser_1.Node(context.source)])])));
|
|
6366
6375
|
exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.focus)(/(?<=^|[\r\n])!?https?:\/\/\S+(?=[^\S\r\n]*(?=$|\r?\n))/y, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, context => {
|
|
6367
6376
|
const {
|
|
6368
6377
|
source,
|
|
@@ -6370,7 +6379,7 @@ exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.focus)(/(?<=^|[\
|
|
|
6370
6379
|
} = context;
|
|
6371
6380
|
context.position -= source[0] === '!' ? 1 : 0;
|
|
6372
6381
|
return new parser_1.List([new parser_1.Node((0, link_1.parse)(new parser_1.List(), new parser_1.List([new parser_1.Node(source.slice(position))]), context))]);
|
|
6373
|
-
})), (
|
|
6382
|
+
})), context => new parser_1.List([new parser_1.Node(context.source)])])])));
|
|
6374
6383
|
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')')), (0, source_1.str)(')'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']')), (0, source_1.str)(']'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}')), (0, source_1.str)('}'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)(source_1.unescsource, '"'))), (0, source_1.str)('"'), true, [3 | 8 /* Backtrack.unescapable */])]));
|
|
6375
6384
|
|
|
6376
6385
|
/***/ },
|
|
@@ -7389,8 +7398,8 @@ const combinator_1 = __webpack_require__(3484);
|
|
|
7389
7398
|
const source_1 = __webpack_require__(8745);
|
|
7390
7399
|
const util_1 = __webpack_require__(4992);
|
|
7391
7400
|
const dom_1 = __webpack_require__(394);
|
|
7392
|
-
const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])
|
|
7393
|
-
exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)(/\$(?={)/y, (0, combinator_1.precedence)(4, bracket), '$', false, [3 | 16 /* Backtrack.escapable */]), (0, combinator_1.surround)(/\$(?![\s{}])/y, (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.escsource,
|
|
7401
|
+
const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
|
|
7402
|
+
exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)(/\$(?={)/y, (0, combinator_1.precedence)(4, bracket), '$', false, [3 | 16 /* Backtrack.escapable */]), (0, combinator_1.surround)(/\$(?![\s{}])/y, (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.escsource, /[`"{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y), (0, combinator_1.precedence)(4, bracket)]))), /(?<!\s)\$(?![-0-9A-Za-z])/y, false, [3 | 16 /* Backtrack.escapable */])]), ({
|
|
7394
7403
|
source,
|
|
7395
7404
|
caches: {
|
|
7396
7405
|
math: cache
|
|
@@ -7404,7 +7413,7 @@ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combin
|
|
|
7404
7413
|
translate: 'no',
|
|
7405
7414
|
...(0, util_1.invalid)('math', 'content', `"${source.match(forbiddenCommand)[0]}" command is forbidden`)
|
|
7406
7415
|
}, source))])));
|
|
7407
|
-
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.escsource, /[{}$\r\n]/y)]))), (0, source_1.str)('}'), true));
|
|
7416
|
+
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.escsource, /[{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y)]))), (0, source_1.str)('}'), true));
|
|
7408
7417
|
|
|
7409
7418
|
/***/ },
|
|
7410
7419
|
|
|
@@ -7666,14 +7675,14 @@ const dom_1 = __webpack_require__(394);
|
|
|
7666
7675
|
exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.inits)([(0, combinator_1.dup)((0, combinator_1.surround)('[', text, ']', false, [1 | 4 /* Backtrack.common */, 3 | 32 /* Backtrack.ruby */], ([, ns]) => {
|
|
7667
7676
|
ns && ns.last?.value === '' && ns.pop();
|
|
7668
7677
|
return (0, visibility_1.isNonblankNodeStart)(ns) ? ns : undefined;
|
|
7669
|
-
})), (0, combinator_1.dup)((0, combinator_1.surround)('(', text, ')', false
|
|
7678
|
+
})), (0, combinator_1.dup)((0, combinator_1.surround)('(', text, ')', false))]), ([{
|
|
7670
7679
|
value: texts
|
|
7671
7680
|
}, {
|
|
7672
7681
|
value: rubies = undefined
|
|
7673
7682
|
} = {}], context) => {
|
|
7674
7683
|
if (rubies === undefined) {
|
|
7675
7684
|
const head = context.position - context.range;
|
|
7676
|
-
return void (0, combinator_1.setBacktrack)(context, 2 | 32 /* Backtrack.ruby */, head);
|
|
7685
|
+
return void (0, combinator_1.setBacktrack)(context, 2 | 64 /* Backtrack.link */ | 32 /* Backtrack.ruby */, head);
|
|
7677
7686
|
}
|
|
7678
7687
|
switch (true) {
|
|
7679
7688
|
case texts.length >= rubies.length:
|
|
@@ -8209,10 +8218,10 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
|
|
|
8209
8218
|
follow = follow > 0 ? follow : countFollows(source, pos, closer, lead / opener.length | 0);
|
|
8210
8219
|
nodes = cons(nodes, context, lead, follow);
|
|
8211
8220
|
if (context.position > pos) {
|
|
8212
|
-
const advance =
|
|
8221
|
+
const advance = context.position - pos;
|
|
8213
8222
|
i -= advance;
|
|
8214
8223
|
follow -= advance;
|
|
8215
|
-
depth -= advance;
|
|
8224
|
+
depth -= advance / closer.length | 0;
|
|
8216
8225
|
}
|
|
8217
8226
|
continue;
|
|
8218
8227
|
}
|
|
@@ -8239,10 +8248,10 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
|
|
|
8239
8248
|
nodes = cons(nodes, context, lead, follow);
|
|
8240
8249
|
state = true;
|
|
8241
8250
|
if (context.position > pos) {
|
|
8242
|
-
const advance =
|
|
8251
|
+
const advance = context.position - pos;
|
|
8243
8252
|
i -= advance;
|
|
8244
8253
|
follow -= advance;
|
|
8245
|
-
depth -= advance;
|
|
8254
|
+
depth -= advance / closer.length | 0;
|
|
8246
8255
|
}
|
|
8247
8256
|
continue;
|
|
8248
8257
|
}
|
|
@@ -8431,14 +8440,11 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
8431
8440
|
exports.escsource = void 0;
|
|
8432
8441
|
const parser_1 = __webpack_require__(605);
|
|
8433
8442
|
const combinator_1 = __webpack_require__(3484);
|
|
8434
|
-
const text_1 = __webpack_require__(5655);
|
|
8435
8443
|
const dom_1 = __webpack_require__(394);
|
|
8436
|
-
const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
|
|
8437
8444
|
const escsource = context => {
|
|
8438
8445
|
const {
|
|
8439
8446
|
source,
|
|
8440
|
-
position
|
|
8441
|
-
state
|
|
8447
|
+
position
|
|
8442
8448
|
} = context;
|
|
8443
8449
|
if (position === source.length) return;
|
|
8444
8450
|
const char = source[position];
|
|
@@ -8467,7 +8473,7 @@ const escsource = context => {
|
|
|
8467
8473
|
return new parser_1.List([new parser_1.Node((0, dom_1.html)('br'), 1 /* Flag.blank */)]);
|
|
8468
8474
|
default:
|
|
8469
8475
|
if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
|
|
8470
|
-
let i = (
|
|
8476
|
+
let i = seek(source, position);
|
|
8471
8477
|
i -= position;
|
|
8472
8478
|
(0, combinator_1.consume)(i - 1, context);
|
|
8473
8479
|
context.position += i - 1;
|
|
@@ -8475,6 +8481,30 @@ const escsource = context => {
|
|
|
8475
8481
|
}
|
|
8476
8482
|
};
|
|
8477
8483
|
exports.escsource = escsource;
|
|
8484
|
+
function seek(source, position) {
|
|
8485
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
8486
|
+
const char = source[i];
|
|
8487
|
+
switch (char) {
|
|
8488
|
+
case '\\':
|
|
8489
|
+
case '$':
|
|
8490
|
+
case '"':
|
|
8491
|
+
case '`':
|
|
8492
|
+
case ':':
|
|
8493
|
+
case '[':
|
|
8494
|
+
case ']':
|
|
8495
|
+
case '(':
|
|
8496
|
+
case ')':
|
|
8497
|
+
case '{':
|
|
8498
|
+
case '}':
|
|
8499
|
+
case '\r':
|
|
8500
|
+
case '\n':
|
|
8501
|
+
return i;
|
|
8502
|
+
default:
|
|
8503
|
+
continue;
|
|
8504
|
+
}
|
|
8505
|
+
}
|
|
8506
|
+
return source.length;
|
|
8507
|
+
}
|
|
8478
8508
|
|
|
8479
8509
|
/***/ },
|
|
8480
8510
|
|
|
@@ -8604,7 +8634,7 @@ exports.strs = strs;
|
|
|
8604
8634
|
Object.defineProperty(exports, "__esModule", ({
|
|
8605
8635
|
value: true
|
|
8606
8636
|
}));
|
|
8607
|
-
exports.isAlphanumeric = exports.
|
|
8637
|
+
exports.isAlphanumeric = exports.backToEmailHead = exports.backToUrlHead = exports.canSkip = exports.txt = exports.text = exports.nonWhitespace = void 0;
|
|
8608
8638
|
const parser_1 = __webpack_require__(605);
|
|
8609
8639
|
const combinator_1 = __webpack_require__(3484);
|
|
8610
8640
|
const dom_1 = __webpack_require__(394);
|
|
@@ -8675,23 +8705,16 @@ function isWhitespace(char, linebreak) {
|
|
|
8675
8705
|
return false;
|
|
8676
8706
|
}
|
|
8677
8707
|
}
|
|
8678
|
-
function next(source, position, state
|
|
8679
|
-
let index;
|
|
8680
|
-
if (
|
|
8681
|
-
delimiter.lastIndex = position + 1;
|
|
8682
|
-
delimiter.test(source);
|
|
8683
|
-
index = delimiter.lastIndex || position;
|
|
8684
|
-
} else {
|
|
8685
|
-
index = seek(source, position, state);
|
|
8686
|
-
}
|
|
8687
|
-
if (index === position || index === source.length) return source.length;
|
|
8708
|
+
function next(source, position, state) {
|
|
8709
|
+
let index = seek(source, position, state);
|
|
8710
|
+
if (index === source.length) return source.length;
|
|
8688
8711
|
const char = source[index];
|
|
8689
8712
|
switch (char) {
|
|
8690
8713
|
case '%':
|
|
8691
|
-
index +=
|
|
8714
|
+
index += index - 1 > position ? -1 : 0;
|
|
8692
8715
|
break;
|
|
8693
8716
|
case '[':
|
|
8694
|
-
index +=
|
|
8717
|
+
index += index - 1 > position && source.startsWith(' [|', index - 1) ? -1 : 0;
|
|
8695
8718
|
break;
|
|
8696
8719
|
case ':':
|
|
8697
8720
|
index = source.startsWith('//', index + 1) ? backToUrlHead(source, position, index) : index;
|
|
@@ -8702,7 +8725,6 @@ function next(source, position, state, delimiter) {
|
|
|
8702
8725
|
}
|
|
8703
8726
|
return index;
|
|
8704
8727
|
}
|
|
8705
|
-
exports.next = next;
|
|
8706
8728
|
function backToUrlHead(source, position, index) {
|
|
8707
8729
|
const delim = index;
|
|
8708
8730
|
let state = false;
|
|
@@ -8724,6 +8746,7 @@ function backToUrlHead(source, position, index) {
|
|
|
8724
8746
|
}
|
|
8725
8747
|
return index === position || source[index] !== 'h' ? delim : index;
|
|
8726
8748
|
}
|
|
8749
|
+
exports.backToUrlHead = backToUrlHead;
|
|
8727
8750
|
function backToEmailHead(source, position, index) {
|
|
8728
8751
|
const delim = index;
|
|
8729
8752
|
let state = false;
|
|
@@ -8746,6 +8769,7 @@ function backToEmailHead(source, position, index) {
|
|
|
8746
8769
|
}
|
|
8747
8770
|
return index === position ? delim : index;
|
|
8748
8771
|
}
|
|
8772
|
+
exports.backToEmailHead = backToEmailHead;
|
|
8749
8773
|
function isAlphanumeric(char) {
|
|
8750
8774
|
if (char < '0' || '\x7F' < char) return false;
|
|
8751
8775
|
return '0' <= char && char <= '9' || 'A' <= char && char <= 'Z' || 'a' <= char && char <= 'z';
|
|
@@ -8841,12 +8865,11 @@ function seek(source, position, state) {
|
|
|
8841
8865
|
Object.defineProperty(exports, "__esModule", ({
|
|
8842
8866
|
value: true
|
|
8843
8867
|
}));
|
|
8844
|
-
exports.unescsource =
|
|
8868
|
+
exports.unescsource = void 0;
|
|
8845
8869
|
const parser_1 = __webpack_require__(605);
|
|
8846
8870
|
const combinator_1 = __webpack_require__(3484);
|
|
8847
8871
|
const text_1 = __webpack_require__(5655);
|
|
8848
8872
|
const dom_1 = __webpack_require__(394);
|
|
8849
|
-
exports.delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
|
|
8850
8873
|
const unescsource = context => {
|
|
8851
8874
|
const {
|
|
8852
8875
|
source,
|
|
@@ -8870,7 +8893,7 @@ const unescsource = context => {
|
|
|
8870
8893
|
default:
|
|
8871
8894
|
if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
|
|
8872
8895
|
text_1.nonWhitespace.lastIndex = position + 1;
|
|
8873
|
-
let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length :
|
|
8896
|
+
let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length : next(source, position, state);
|
|
8874
8897
|
i -= position;
|
|
8875
8898
|
(0, combinator_1.consume)(i - 1, context);
|
|
8876
8899
|
context.position += i - 1;
|
|
@@ -8878,6 +8901,79 @@ const unescsource = context => {
|
|
|
8878
8901
|
}
|
|
8879
8902
|
};
|
|
8880
8903
|
exports.unescsource = unescsource;
|
|
8904
|
+
function next(source, position, state) {
|
|
8905
|
+
let index = seek(source, position, state);
|
|
8906
|
+
if (index === source.length) return source.length;
|
|
8907
|
+
const char = source[index];
|
|
8908
|
+
switch (char) {
|
|
8909
|
+
case ':':
|
|
8910
|
+
index = source.startsWith('//', index + 1) ? (0, text_1.backToUrlHead)(source, position, index) : index;
|
|
8911
|
+
break;
|
|
8912
|
+
case '@':
|
|
8913
|
+
index = ~state & 1 /* State.autolink */ ? (0, text_1.backToEmailHead)(source, position, index) : index;
|
|
8914
|
+
break;
|
|
8915
|
+
}
|
|
8916
|
+
return index;
|
|
8917
|
+
}
|
|
8918
|
+
function seek(source, position, state) {
|
|
8919
|
+
const cat = category(source[position]);
|
|
8920
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
8921
|
+
const char = source[i];
|
|
8922
|
+
switch (char) {
|
|
8923
|
+
case '\\':
|
|
8924
|
+
case '!':
|
|
8925
|
+
case '$':
|
|
8926
|
+
case '"':
|
|
8927
|
+
case '`':
|
|
8928
|
+
case '[':
|
|
8929
|
+
case ']':
|
|
8930
|
+
case '(':
|
|
8931
|
+
case ')':
|
|
8932
|
+
case '{':
|
|
8933
|
+
case '}':
|
|
8934
|
+
case '<':
|
|
8935
|
+
case '>':
|
|
8936
|
+
case '(':
|
|
8937
|
+
case ')':
|
|
8938
|
+
case '[':
|
|
8939
|
+
case ']':
|
|
8940
|
+
case '{':
|
|
8941
|
+
case '}':
|
|
8942
|
+
case '-':
|
|
8943
|
+
case '+':
|
|
8944
|
+
case '*':
|
|
8945
|
+
case '=':
|
|
8946
|
+
case '~':
|
|
8947
|
+
case '^':
|
|
8948
|
+
case '_':
|
|
8949
|
+
case ',':
|
|
8950
|
+
case '.':
|
|
8951
|
+
case ';':
|
|
8952
|
+
case ':':
|
|
8953
|
+
case '!':
|
|
8954
|
+
case '?':
|
|
8955
|
+
case '/':
|
|
8956
|
+
case '|':
|
|
8957
|
+
case '\r':
|
|
8958
|
+
case '\n':
|
|
8959
|
+
return i;
|
|
8960
|
+
case '@':
|
|
8961
|
+
case '#':
|
|
8962
|
+
if (~state & 1 /* State.autolink */) return i;
|
|
8963
|
+
continue;
|
|
8964
|
+
case ':':
|
|
8965
|
+
if (source[i + 1] === '/' && source[i + 2] === '/') return i;
|
|
8966
|
+
continue;
|
|
8967
|
+
default:
|
|
8968
|
+
if (cat && !category(char)) return i;
|
|
8969
|
+
continue;
|
|
8970
|
+
}
|
|
8971
|
+
}
|
|
8972
|
+
return source.length;
|
|
8973
|
+
}
|
|
8974
|
+
function category(char) {
|
|
8975
|
+
return '\x21' <= char && char <= '\x7E';
|
|
8976
|
+
}
|
|
8881
8977
|
|
|
8882
8978
|
/***/ },
|
|
8883
8979
|
|
package/markdown.d.ts
CHANGED
|
@@ -1082,7 +1082,7 @@ export namespace MarkdownParser {
|
|
|
1082
1082
|
Inline<'url'>,
|
|
1083
1083
|
Parser<string | HTMLElement, Context, [
|
|
1084
1084
|
Parser<HTMLAnchorElement, Context, []>,
|
|
1085
|
-
|
|
1085
|
+
Parser<string, Context, []>,
|
|
1086
1086
|
]> {
|
|
1087
1087
|
}
|
|
1088
1088
|
export namespace UrlParser {
|
|
@@ -1092,7 +1092,7 @@ export namespace MarkdownParser {
|
|
|
1092
1092
|
SourceParser.StrParser,
|
|
1093
1093
|
Parser<string | HTMLElement, Context, [
|
|
1094
1094
|
Parser<HTMLAnchorElement, Context, []>,
|
|
1095
|
-
|
|
1095
|
+
Parser<string, Context, []>,
|
|
1096
1096
|
]>,
|
|
1097
1097
|
]> {
|
|
1098
1098
|
}
|
package/package.json
CHANGED
|
@@ -4,24 +4,31 @@ import { Delimiters } from '../delimiter';
|
|
|
4
4
|
type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
|
|
5
5
|
|
|
6
6
|
export function some<P extends Parser>(parser: P, limit?: number): P;
|
|
7
|
-
export function some<P extends Parser>(parser: P, delimiters?: readonly DelimiterOption[]): P;
|
|
8
|
-
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, delimiters?: readonly DelimiterOption[]): P;
|
|
9
|
-
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, after: string | RegExp, delimiters?: readonly DelimiterOption[]): P;
|
|
10
|
-
export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp | readonly DelimiterOption[], after?: string | RegExp | readonly DelimiterOption[], delimiters?: readonly DelimiterOption[], limit =
|
|
7
|
+
export function some<P extends Parser>(parser: P, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
8
|
+
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
9
|
+
export function some<P extends Parser>(parser: P, delimiter: string | RegExp, after: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
|
|
10
|
+
export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp | readonly DelimiterOption[], after?: number | string | RegExp | readonly DelimiterOption[], delimiters?: number | readonly DelimiterOption[], limit = 0): Parser<N> {
|
|
11
11
|
if (typeof delimiter === 'number') {
|
|
12
12
|
limit = delimiter;
|
|
13
|
+
delimiters = undefined;
|
|
13
14
|
delimiter = undefined;
|
|
14
15
|
}
|
|
15
16
|
else if (Array.isArray(delimiter)) {
|
|
17
|
+
limit = after as number;
|
|
16
18
|
delimiters = delimiter;
|
|
17
19
|
delimiter = undefined;
|
|
18
20
|
}
|
|
19
21
|
else if (after === undefined || Array.isArray(after)) {
|
|
22
|
+
limit = delimiters as number;
|
|
20
23
|
delimiters = after;
|
|
21
24
|
after = undefined;
|
|
22
25
|
}
|
|
26
|
+
else {
|
|
27
|
+
delimiters = delimiters as readonly DelimiterOption[];
|
|
28
|
+
}
|
|
23
29
|
assert(parser);
|
|
24
30
|
assert(delimiter !== '');
|
|
31
|
+
assert(delimiters === undefined || Array.isArray(delimiters));
|
|
25
32
|
const match = Delimiters.tester(delimiter as string, after as string);
|
|
26
33
|
const delims = delimiters?.map(([delimiter, precedence]) => ({
|
|
27
34
|
signature: Delimiters.signature(delimiter),
|
|
@@ -43,7 +50,8 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
|
|
|
43
50
|
if (result === undefined) break;
|
|
44
51
|
if (context.position === pos) break;
|
|
45
52
|
nodes = nodes?.import(result) ?? result;
|
|
46
|
-
|
|
53
|
+
// 次にパースに成功すれば確実に制限値を超えるので制限値ちょうどでも中止する
|
|
54
|
+
if (limit > 0 && context.position - position >= limit) break;
|
|
47
55
|
}
|
|
48
56
|
delims && context.delimiters.pop(delims.length);
|
|
49
57
|
assert(context.position >= position);
|
package/src/parser/api/header.ts
CHANGED
|
@@ -8,7 +8,11 @@ export function header(source: string): string {
|
|
|
8
8
|
|
|
9
9
|
export function headers(source: string): string[] {
|
|
10
10
|
const [el] = parse(source);
|
|
11
|
-
|
|
11
|
+
const acc = [];
|
|
12
|
+
for (let field = el?.firstChild?.firstChild; field = field?.nextSibling;) {
|
|
13
|
+
acc.push(field.textContent!);
|
|
14
|
+
}
|
|
15
|
+
return acc;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
function parse(source: string): [HTMLElement, number] | [] {
|
|
@@ -125,7 +125,7 @@ describe('Unit: parser/api/parse', () => {
|
|
|
125
125
|
'!{../../a}',
|
|
126
126
|
].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => el.outerHTML),
|
|
127
127
|
[
|
|
128
|
-
'<aside class="header"><details open=""><summary>Header</summary><
|
|
128
|
+
'<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span></div></details></aside>',
|
|
129
129
|
'<p><a class="account" href="https://source/@a" target="_blank">@a</a></p>',
|
|
130
130
|
'<p><a class="account" href="https://domain/@a" target="_blank">@domain/a</a></p>',
|
|
131
131
|
'<p><a class="channel" href="https://source/@a?ch=b" target="_blank">@a#b</a></p>',
|
|
@@ -158,7 +158,7 @@ describe('Unit: parser/api/parse', () => {
|
|
|
158
158
|
'{./a}',
|
|
159
159
|
].join('\n\n'), { host: new URL(`${location.origin}/index.md`) }).children].map(el => el.outerHTML),
|
|
160
160
|
[
|
|
161
|
-
'<aside class="header"><details open=""><summary>Header</summary><
|
|
161
|
+
'<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span></div></details></aside>',
|
|
162
162
|
'<p><a class="url" href="/a">^/a</a></p>',
|
|
163
163
|
'<p><a class="url" href="https://source/x/a" target="_blank">./a</a></p>',
|
|
164
164
|
]);
|
|
@@ -173,7 +173,7 @@ describe('Unit: parser/api/parse', () => {
|
|
|
173
173
|
'{./a}',
|
|
174
174
|
].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => el.outerHTML),
|
|
175
175
|
[
|
|
176
|
-
`<aside class="header"><details open=""><summary>Header</summary><
|
|
176
|
+
`<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="${location.origin}/x/y"><span class="field-name">URL</span>: <span class="field-value">${location.origin}/x/y</span></div></details></aside>`,
|
|
177
177
|
'<p><a class="url" href="/z/a">^/a</a></p>',
|
|
178
178
|
'<p><a class="url" href="/x/a">./a</a></p>',
|
|
179
179
|
]);
|
|
@@ -204,9 +204,9 @@ describe('Unit: parser/api/parse', () => {
|
|
|
204
204
|
'{#}',
|
|
205
205
|
].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => normalize(el.outerHTML)),
|
|
206
206
|
[
|
|
207
|
-
`<aside class="header"><details open=""><summary>Header</summary><
|
|
207
|
+
`<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://example/x"><span class="field-name">URL</span>: <span class="field-value">https://example/x</span></div></details></aside>`,
|
|
208
208
|
'<pre class="invalid" translate="no">---\nURL: https://example/y\n---\n</pre>',
|
|
209
|
-
'<aside class="example" data-type="markdown"><pre translate="no">---\nURL: https://example/y\n---\n\n{#}</pre><hr><section><aside class="header"><details open=""><summary>Header</summary><
|
|
209
|
+
'<aside class="example" data-type="markdown"><pre translate="no">---\nURL: https://example/y\n---\n\n{#}</pre><hr><section><aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://example/y"><span class="field-name">URL</span>: <span class="field-value">https://example/y</span></div></details></aside><p><a class="url" href="https://example/y#" target="_blank">#</a></p><h2>References</h2><ol class="references"></ol></section></aside>',
|
|
210
210
|
'<p><a class="url" href="https://example/x#" target="_blank">#</a></p>',
|
|
211
211
|
]);
|
|
212
212
|
});
|
|
@@ -380,28 +380,28 @@ describe('Unit: parser/api/parse', () => {
|
|
|
380
380
|
// 最悪計算量での実行速度はCommonMarkの公式JS実装の32nに対して1-4倍程度。
|
|
381
381
|
// 5n = reference + link + url/math + ruby + text
|
|
382
382
|
assert.deepStrictEqual(
|
|
383
|
-
[...parse(`((([[[[#$[${'.'.repeat(
|
|
383
|
+
[...parse(`((([[[[#$http://[${'.'.repeat(19992)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
|
|
384
384
|
.map(el => el.tagName),
|
|
385
385
|
['P']);
|
|
386
386
|
});
|
|
387
387
|
|
|
388
388
|
it('backtrack 1 error', () => {
|
|
389
389
|
assert.deepStrictEqual(
|
|
390
|
-
[...parse(`((([[[[#$[${'.'.repeat(
|
|
390
|
+
[...parse(`((([[[[#$http://[${'.'.repeat(19992 + 1)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
|
|
391
391
|
.map(el => el.tagName),
|
|
392
392
|
['H1', 'PRE']);
|
|
393
393
|
});
|
|
394
394
|
|
|
395
395
|
it('backtrack 2', () => {
|
|
396
396
|
assert.deepStrictEqual(
|
|
397
|
-
[...parse(`((([[[[#$[${'.'.repeat(
|
|
397
|
+
[...parse(`((([[[[#$http://[${'.'.repeat(33324)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
|
|
398
398
|
.map(el => el.tagName),
|
|
399
399
|
['P', 'OL']);
|
|
400
400
|
});
|
|
401
401
|
|
|
402
402
|
it('backtrack 2 error', () => {
|
|
403
403
|
assert.deepStrictEqual(
|
|
404
|
-
[...parse(`((([[[[#$[${'.'.repeat(
|
|
404
|
+
[...parse(`((([[[[#$http://[${'.'.repeat(33324 + 1)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
|
|
405
405
|
.map(el => el.tagName),
|
|
406
406
|
['H1', 'PRE']);
|
|
407
407
|
});
|
package/src/parser/context.ts
CHANGED
|
@@ -24,11 +24,11 @@ describe('Unit: parser/header', () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('basic', () => {
|
|
27
|
-
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><
|
|
28
|
-
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><
|
|
29
|
-
assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><
|
|
30
|
-
assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><
|
|
31
|
-
assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><
|
|
27
|
+
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
});
|
package/src/parser/header.ts
CHANGED
|
@@ -11,7 +11,7 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
|
|
|
11
11
|
block(
|
|
12
12
|
union([
|
|
13
13
|
validate(context => context.header,
|
|
14
|
-
focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,
|
|
14
|
+
focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi,
|
|
15
15
|
convert(source =>
|
|
16
16
|
source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')),
|
|
17
17
|
fmap(
|
|
@@ -42,11 +42,10 @@ const field: MarkdownParser.HeaderParser.FieldParser = line(({ source, position
|
|
|
42
42
|
const name = source.slice(position, source.indexOf(':', position));
|
|
43
43
|
const value = source.slice(position + name.length + 1).trim();
|
|
44
44
|
return new List([
|
|
45
|
-
new Node(html('
|
|
45
|
+
new Node(html('div', { class: 'field', 'data-name': name.toLowerCase(), 'data-value': value }, [
|
|
46
46
|
html('span', { class: 'field-name' }, name),
|
|
47
47
|
': ',
|
|
48
48
|
html('span', { class: 'field-value' }, value),
|
|
49
|
-
'\n',
|
|
50
49
|
])),
|
|
51
50
|
]);
|
|
52
51
|
});
|
|
@@ -41,17 +41,22 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
41
41
|
new Node(html('span', { class: bracketname(context, 1, 1) }, defrag(unwrap(nodes))))
|
|
42
42
|
]);
|
|
43
43
|
}
|
|
44
|
-
recursion.add(
|
|
44
|
+
recursion.add(
|
|
45
|
+
MAX_DEPTH - (resources?.recursions[Recursion.bracket] ?? resources?.recursions.at(-1) ?? MAX_DEPTH));
|
|
45
46
|
context.position += 1;
|
|
46
47
|
return new List([
|
|
47
|
-
new Node(html('sup', { class: 'annotation' }, [
|
|
48
|
+
new Node(html('sup', { class: 'annotation' }, [
|
|
49
|
+
html('span', defrag(unwrap(trimBlankNodeEnd(nodes))))
|
|
50
|
+
]))
|
|
48
51
|
]);
|
|
49
52
|
},
|
|
50
53
|
(nodes, context, prefix, postfix) => {
|
|
51
54
|
assert(postfix === 0);
|
|
52
55
|
for (let i = 0; i < prefix; ++i) {
|
|
53
56
|
nodes.unshift(new Node('('));
|
|
54
|
-
nodes = new List([
|
|
57
|
+
nodes = new List([
|
|
58
|
+
new Node(html('span', { class: bracketname(context, 0, 0) }, defrag(unwrap(nodes))))
|
|
59
|
+
]);
|
|
55
60
|
context.range += 1;
|
|
56
61
|
}
|
|
57
62
|
return nodes;
|
|
@@ -2,13 +2,12 @@ import { AutolinkParser } from '../../inline';
|
|
|
2
2
|
import { State, Recursion, Backtrack } from '../../context';
|
|
3
3
|
import { List, Node } from '../../../combinator/data/parser';
|
|
4
4
|
import { union, tails, some, recursion, precedence, state, constraint, focus, rewrite, surround, open, lazy } from '../../../combinator';
|
|
5
|
-
import { inline } from '../../inline';
|
|
6
5
|
import { parse } from '../link';
|
|
7
6
|
import { unescsource, str } from '../../source';
|
|
8
7
|
|
|
9
8
|
export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
|
|
10
9
|
open(
|
|
11
|
-
/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[
|
|
10
|
+
/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[[0-9A-Za-z])/y,
|
|
12
11
|
precedence(0, some(union([
|
|
13
12
|
some(unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y),
|
|
14
13
|
precedence(1, bracket),
|
|
@@ -18,7 +17,7 @@ export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
|
|
|
18
17
|
union([
|
|
19
18
|
constraint(State.autolink, state(State.autolink, context =>
|
|
20
19
|
new List([new Node(parse(new List(), new List([new Node(context.source)]), context))]))),
|
|
21
|
-
|
|
20
|
+
context => new List([new Node(context.source)]),
|
|
22
21
|
])));
|
|
23
22
|
|
|
24
23
|
export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
|
|
@@ -36,7 +35,7 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
|
|
|
36
35
|
context))
|
|
37
36
|
]);
|
|
38
37
|
})),
|
|
39
|
-
|
|
38
|
+
context => new List([new Node(context.source)]),
|
|
40
39
|
]),
|
|
41
40
|
])));
|
|
42
41
|
|
|
@@ -93,8 +93,8 @@ describe('Unit: parser/inline/math', () => {
|
|
|
93
93
|
assert.deepStrictEqual(inspect(parser, input('$\\Begin$', new Context())), [['<span class="invalid" translate="no">$\\Begin$</span>'], '']);
|
|
94
94
|
assert.deepStrictEqual(inspect(parser, input('$\\begin{}$', new Context())), [['<span class="invalid" translate="no">$\\begin{}$</span>'], '']);
|
|
95
95
|
assert.deepStrictEqual(inspect(parser, input('${\\begin}$', new Context())), [['<span class="invalid" translate="no">${\\begin}$</span>'], '']);
|
|
96
|
-
assert.deepStrictEqual(inspect(parser, input('$http://host$', new Context())),
|
|
97
|
-
assert.deepStrictEqual(inspect(parser, input('${http://host}$', new Context())),
|
|
96
|
+
assert.deepStrictEqual(inspect(parser, input('$http://host$', new Context())), undefined);
|
|
97
|
+
assert.deepStrictEqual(inspect(parser, input('${http://host}$', new Context())), undefined);
|
|
98
98
|
assert.deepStrictEqual(inspect(parser, input(' ${a}$', new Context())), undefined);
|
|
99
99
|
});
|
|
100
100
|
|
|
@@ -6,7 +6,7 @@ import { escsource, str } from '../source';
|
|
|
6
6
|
import { invalid } from '../util';
|
|
7
7
|
import { html } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
|
-
const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])
|
|
9
|
+
const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
|
|
10
10
|
|
|
11
11
|
export const math: MathParser = lazy(() => rewrite(
|
|
12
12
|
union([
|
|
@@ -19,7 +19,7 @@ export const math: MathParser = lazy(() => rewrite(
|
|
|
19
19
|
surround(
|
|
20
20
|
/\$(?![\s{}])/y,
|
|
21
21
|
precedence(2, some(union([
|
|
22
|
-
some(escsource,
|
|
22
|
+
some(escsource, /[`"{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y),
|
|
23
23
|
precedence(4, bracket),
|
|
24
24
|
]))),
|
|
25
25
|
/(?<!\s)\$(?![-0-9A-Za-z])/y,
|
|
@@ -45,7 +45,7 @@ const bracket: MathParser.BracketParser = lazy(() => surround(
|
|
|
45
45
|
recursion(Recursion.terminal,
|
|
46
46
|
some(union([
|
|
47
47
|
bracket,
|
|
48
|
-
some(escsource, /[{}$\r\n]/y),
|
|
48
|
+
some(escsource, /[{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y),
|
|
49
49
|
]))),
|
|
50
50
|
str('}'),
|
|
51
51
|
true));
|
|
@@ -20,13 +20,12 @@ export const ruby: RubyParser = lazy(() => bind(
|
|
|
20
20
|
})),
|
|
21
21
|
dup(surround(
|
|
22
22
|
'(', text, ')',
|
|
23
|
-
false,
|
|
24
|
-
[3 | Backtrack.ruby])),
|
|
23
|
+
false)),
|
|
25
24
|
]),
|
|
26
25
|
([{ value: texts }, { value: rubies = undefined } = {}], context) => {
|
|
27
26
|
if (rubies === undefined) {
|
|
28
27
|
const head = context.position - context.range;
|
|
29
|
-
return void setBacktrack(context, 2 | Backtrack.ruby, head);
|
|
28
|
+
return void setBacktrack(context, 2 | Backtrack.link | Backtrack.ruby, head);
|
|
30
29
|
}
|
|
31
30
|
switch (true) {
|
|
32
31
|
case texts.length >= rubies.length:
|
|
@@ -167,7 +167,7 @@ describe('Unit: parser/inline', () => {
|
|
|
167
167
|
assert.deepStrictEqual(inspect(parser, input('"[% "*"* %]', new Context())), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
|
|
168
168
|
assert.deepStrictEqual(inspect(parser, input('"{{""}}', new Context())), [['"', '{', '<a class="url" href="""">""</a>', '}'], '']);
|
|
169
169
|
assert.deepStrictEqual(inspect(parser, input('[#http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::http://host/(<bdi>)">http://host/<span class="paren">(<span class="invalid"><bdi></span>)</span></a>', '</bdi', '>'], '']);
|
|
170
|
-
assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host
|
|
170
|
+
assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(<bdi>)">@a/http://host/(<bdi>)</a>', '</bdi', '>'], '']);
|
|
171
171
|
assert.deepStrictEqual(inspect(parser, input('[#a|<bdi>]</bdi>', new Context())), [['<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
172
172
|
assert.deepStrictEqual(inspect(parser, input('[[#a|<bdi>]</bdi>', new Context())), [['[', '<a class="index" href="#index::a|<bdi>">a|<span class="invalid"><bdi></span></a>', '</bdi', '>'], '']);
|
|
173
173
|
assert.deepStrictEqual(inspect(parser, input('[*==*]{a}', new Context())), [['<a class="link" href="a">*==*</a>'], '']);
|
package/src/parser/repeat.ts
CHANGED
|
@@ -68,10 +68,10 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
68
68
|
follow = follow > 0 ? follow : countFollows(source, pos, closer, lead / opener.length | 0);
|
|
69
69
|
nodes = cons(nodes, context, lead, follow);
|
|
70
70
|
if (context.position > pos) {
|
|
71
|
-
const advance =
|
|
71
|
+
const advance = context.position - pos;
|
|
72
72
|
i -= advance;
|
|
73
73
|
follow -= advance;
|
|
74
|
-
depth -= advance;
|
|
74
|
+
depth -= advance / closer.length | 0;
|
|
75
75
|
}
|
|
76
76
|
continue;
|
|
77
77
|
}
|
|
@@ -100,10 +100,10 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
100
100
|
nodes = cons(nodes, context, lead, follow);
|
|
101
101
|
state = true;
|
|
102
102
|
if (context.position > pos) {
|
|
103
|
-
const advance =
|
|
103
|
+
const advance = context.position - pos;
|
|
104
104
|
i -= advance;
|
|
105
105
|
follow -= advance;
|
|
106
|
-
depth -= advance;
|
|
106
|
+
depth -= advance / closer.length | 0;
|
|
107
107
|
}
|
|
108
108
|
continue;
|
|
109
109
|
}
|
|
@@ -3,13 +3,10 @@ import { Command } from '../context';
|
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
5
|
import { consume } from '../../combinator';
|
|
6
|
-
import { next } from './text';
|
|
7
6
|
import { html } from 'typed-dom/dom';
|
|
8
7
|
|
|
9
|
-
const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
|
|
10
|
-
|
|
11
8
|
export const escsource: EscapableSourceParser = context => {
|
|
12
|
-
const { source, position
|
|
9
|
+
const { source, position } = context;
|
|
13
10
|
if (position === source.length) return;
|
|
14
11
|
const char = source[position];
|
|
15
12
|
consume(1, context);
|
|
@@ -38,7 +35,7 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
38
35
|
default:
|
|
39
36
|
assert(char !== '\n');
|
|
40
37
|
if (context.sequential) return new List([new Node(char)]);
|
|
41
|
-
let i =
|
|
38
|
+
let i = seek(source, position);
|
|
42
39
|
assert(i > position);
|
|
43
40
|
i -= position;
|
|
44
41
|
consume(i - 1, context);
|
|
@@ -46,3 +43,29 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
46
43
|
return new List([new Node(source.slice(position, context.position))]);
|
|
47
44
|
}
|
|
48
45
|
};
|
|
46
|
+
|
|
47
|
+
function seek(source: string, position: number): number {
|
|
48
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
49
|
+
const char = source[i];
|
|
50
|
+
switch (char) {
|
|
51
|
+
case '\\':
|
|
52
|
+
case '$':
|
|
53
|
+
case '"':
|
|
54
|
+
case '`':
|
|
55
|
+
case ':':
|
|
56
|
+
case '[':
|
|
57
|
+
case ']':
|
|
58
|
+
case '(':
|
|
59
|
+
case ')':
|
|
60
|
+
case '{':
|
|
61
|
+
case '}':
|
|
62
|
+
case '\r':
|
|
63
|
+
case '\n':
|
|
64
|
+
return i;
|
|
65
|
+
default:
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
assert(false);
|
|
69
|
+
}
|
|
70
|
+
return source.length;
|
|
71
|
+
}
|
|
@@ -83,28 +83,20 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
let index
|
|
88
|
-
if (delimiter) {
|
|
89
|
-
delimiter.lastIndex = position + 1;
|
|
90
|
-
delimiter.test(source);
|
|
91
|
-
index = delimiter.lastIndex || position;
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
index = seek(source, position, state);
|
|
95
|
-
}
|
|
96
|
-
if (index === position || index === source.length) return source.length;
|
|
86
|
+
function next(source: string, position: number, state: number): number {
|
|
87
|
+
let index= seek(source, position, state);
|
|
97
88
|
assert(index > position);
|
|
89
|
+
if (index === source.length) return source.length;
|
|
98
90
|
const char = source[index];
|
|
99
91
|
switch (char) {
|
|
100
92
|
case '%':
|
|
101
|
-
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true)
|
|
102
|
-
index +=
|
|
93
|
+
assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true));
|
|
94
|
+
index += index - 1 > position
|
|
103
95
|
? -1
|
|
104
96
|
: 0;
|
|
105
97
|
break;
|
|
106
98
|
case '[':
|
|
107
|
-
index +=
|
|
99
|
+
index += index - 1 > position && source.startsWith(' [|', index - 1)
|
|
108
100
|
? -1
|
|
109
101
|
: 0;
|
|
110
102
|
break;
|
|
@@ -122,7 +114,7 @@ export function next(source: string, position: number, state: number, delimiter?
|
|
|
122
114
|
assert(index > position);
|
|
123
115
|
return index;
|
|
124
116
|
}
|
|
125
|
-
function backToUrlHead(source: string, position: number, index: number): number {
|
|
117
|
+
export function backToUrlHead(source: string, position: number, index: number): number {
|
|
126
118
|
const delim = index;
|
|
127
119
|
let state = false;
|
|
128
120
|
for (let i = index - 1; i >= position; --i) {
|
|
@@ -145,7 +137,7 @@ function backToUrlHead(source: string, position: number, index: number): number
|
|
|
145
137
|
? delim
|
|
146
138
|
: index;
|
|
147
139
|
}
|
|
148
|
-
function backToEmailHead(source: string, position: number, index: number): number {
|
|
140
|
+
export function backToEmailHead(source: string, position: number, index: number): number {
|
|
149
141
|
const delim = index;
|
|
150
142
|
let state = false;
|
|
151
143
|
for (let i = index - 1; i >= position; --i) {
|
|
@@ -15,7 +15,7 @@ describe('Unit: parser/source/unescapable', () => {
|
|
|
15
15
|
it('basic', () => {
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('a', new Context())), [['a'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser, input('ab', new Context())), [['ab'], '']);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b
|
|
18
|
+
assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b c'], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser, input('09あいAZaz', new Context())), [['09', 'あいAZaz'], '']);
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { UnescapableSourceParser } from '../source';
|
|
2
|
-
import { Command } from '../context';
|
|
2
|
+
import { State, Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
5
|
import { consume } from '../../combinator';
|
|
6
|
-
import { nonWhitespace, canSkip,
|
|
6
|
+
import { nonWhitespace, canSkip, backToUrlHead, backToEmailHead } from './text';
|
|
7
7
|
import { html } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
|
-
export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
|
|
10
|
-
|
|
11
9
|
export const unescsource: UnescapableSourceParser = context => {
|
|
12
10
|
const { source, position, state } = context;
|
|
13
11
|
if (position === source.length) return;
|
|
@@ -32,7 +30,7 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
32
30
|
? nonWhitespace.test(source)
|
|
33
31
|
? nonWhitespace.lastIndex - 1
|
|
34
32
|
: source.length
|
|
35
|
-
: next(source, position, state
|
|
33
|
+
: next(source, position, state);
|
|
36
34
|
assert(i > position);
|
|
37
35
|
i -= position;
|
|
38
36
|
consume(i - 1, context);
|
|
@@ -40,3 +38,86 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
40
38
|
return new List([new Node(source.slice(position, context.position))]);
|
|
41
39
|
}
|
|
42
40
|
};
|
|
41
|
+
|
|
42
|
+
function next(source: string, position: number, state: number): number {
|
|
43
|
+
let index= seek(source, position, state);
|
|
44
|
+
assert(index > position);
|
|
45
|
+
if (index === source.length) return source.length;
|
|
46
|
+
const char = source[index];
|
|
47
|
+
switch (char) {
|
|
48
|
+
case ':':
|
|
49
|
+
index = source.startsWith('//', index + 1)
|
|
50
|
+
? backToUrlHead(source, position, index)
|
|
51
|
+
: index;
|
|
52
|
+
break;
|
|
53
|
+
case '@':
|
|
54
|
+
index = ~state & State.autolink
|
|
55
|
+
? backToEmailHead(source, position, index)
|
|
56
|
+
: index;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
assert(index > position);
|
|
60
|
+
return index;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function seek(source: string, position: number, state: number): number {
|
|
64
|
+
const cat = category(source[position]);
|
|
65
|
+
for (let i = position + 1; i < source.length; ++i) {
|
|
66
|
+
const char = source[i];
|
|
67
|
+
switch (char) {
|
|
68
|
+
case '\\':
|
|
69
|
+
case '!':
|
|
70
|
+
case '$':
|
|
71
|
+
case '"':
|
|
72
|
+
case '`':
|
|
73
|
+
case '[':
|
|
74
|
+
case ']':
|
|
75
|
+
case '(':
|
|
76
|
+
case ')':
|
|
77
|
+
case '{':
|
|
78
|
+
case '}':
|
|
79
|
+
case '<':
|
|
80
|
+
case '>':
|
|
81
|
+
case '(':
|
|
82
|
+
case ')':
|
|
83
|
+
case '[':
|
|
84
|
+
case ']':
|
|
85
|
+
case '{':
|
|
86
|
+
case '}':
|
|
87
|
+
case '-':
|
|
88
|
+
case '+':
|
|
89
|
+
case '*':
|
|
90
|
+
case '=':
|
|
91
|
+
case '~':
|
|
92
|
+
case '^':
|
|
93
|
+
case '_':
|
|
94
|
+
case ',':
|
|
95
|
+
case '.':
|
|
96
|
+
case ';':
|
|
97
|
+
case ':':
|
|
98
|
+
case '!':
|
|
99
|
+
case '?':
|
|
100
|
+
case '/':
|
|
101
|
+
case '|':
|
|
102
|
+
case '\r':
|
|
103
|
+
case '\n':
|
|
104
|
+
return i;
|
|
105
|
+
case '@':
|
|
106
|
+
case '#':
|
|
107
|
+
if (~state & State.autolink) return i;
|
|
108
|
+
continue;
|
|
109
|
+
case ':':
|
|
110
|
+
if (source[i + 1] === '/' && source[i + 2] === '/') return i;
|
|
111
|
+
continue;
|
|
112
|
+
default:
|
|
113
|
+
if (cat && !category(char)) return i;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
assert(false);
|
|
117
|
+
}
|
|
118
|
+
return source.length;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function category(char: string): boolean {
|
|
122
|
+
return '\x21' <= char && char <= '\x7E';
|
|
123
|
+
}
|