securemark 0.299.2 → 0.299.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/index.js +58 -100
- package/package.json +1 -1
- package/src/combinator/control/manipulation/fence.ts +2 -2
- package/src/combinator/control/manipulation/match.ts +2 -2
- package/src/combinator/data/delimiter.ts +3 -3
- package/src/combinator/data/parser/context.ts +12 -38
- package/src/combinator/data/parser/some.ts +0 -1
- package/src/parser/block/blockquote.ts +2 -2
- package/src/parser/block.ts +1 -1
- package/src/parser/context.ts +4 -5
- package/src/parser/inline/annotation.ts +1 -1
- package/src/parser/inline/deletion.ts +1 -1
- package/src/parser/inline/emstrong.ts +1 -1
- package/src/parser/inline/insertion.ts +1 -1
- package/src/parser/inline/italic.ts +1 -1
- package/src/parser/inline/link.ts +2 -2
- package/src/parser/inline/mark.ts +1 -1
- package/src/parser/inline/media.ts +2 -2
- package/src/parser/inline.ts +1 -1
- package/src/parser/repeat.ts +7 -19
- package/src/parser/source/escapable.ts +5 -5
- package/src/parser/source/text.ts +8 -9
- package/src/parser/source/unescapable.ts +6 -6
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.299.
|
|
1
|
+
/*! securemark v0.299.3 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
|
|
2
2
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
3
3
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
4
4
|
module.exports = factory(require("Prism"), require("DOMPurify"));
|
|
@@ -2605,7 +2605,7 @@ function fence(opener, limit, separation = true) {
|
|
|
2605
2605
|
opener.lastIndex = position;
|
|
2606
2606
|
const matches = opener.exec(source);
|
|
2607
2607
|
if (!matches) return;
|
|
2608
|
-
(0, combinator_1.
|
|
2608
|
+
(0, combinator_1.spend)(context, matches[0].length);
|
|
2609
2609
|
const delim = matches[1];
|
|
2610
2610
|
if (matches[0].includes(delim, delim.length)) return;
|
|
2611
2611
|
context.position += matches[0].length;
|
|
@@ -2727,7 +2727,7 @@ function match(pattern, f) {
|
|
|
2727
2727
|
pattern.lastIndex = position;
|
|
2728
2728
|
const params = pattern.exec(source);
|
|
2729
2729
|
if (!params) return;
|
|
2730
|
-
count && (0, combinator_1.
|
|
2730
|
+
count && (0, combinator_1.spend)(context, params[0].length);
|
|
2731
2731
|
const result = f(params)(input);
|
|
2732
2732
|
context.position += result ? context.position === position ? params[0].length : 0 : context.position - position;
|
|
2733
2733
|
return result;
|
|
@@ -3239,7 +3239,7 @@ function matcher(pattern, advance, after) {
|
|
|
3239
3239
|
pos = position;
|
|
3240
3240
|
if (index === -1) return;
|
|
3241
3241
|
const src = source.slice(position, index);
|
|
3242
|
-
count && !hit && (0, context_1.
|
|
3242
|
+
count && !hit && (0, context_1.spend)(context, src.length);
|
|
3243
3243
|
if (advance) {
|
|
3244
3244
|
context.position = index;
|
|
3245
3245
|
}
|
|
@@ -3290,7 +3290,7 @@ function tester(pattern, advance, after) {
|
|
|
3290
3290
|
pos = position;
|
|
3291
3291
|
if (index === -1) return;
|
|
3292
3292
|
const len = index - position;
|
|
3293
|
-
count && !hit && (0, context_1.
|
|
3293
|
+
count && !hit && (0, context_1.spend)(context, len);
|
|
3294
3294
|
if (advance) {
|
|
3295
3295
|
context.position = index;
|
|
3296
3296
|
}
|
|
@@ -3547,35 +3547,28 @@ exports.failsafe = failsafe;
|
|
|
3547
3547
|
Object.defineProperty(exports, "__esModule", ({
|
|
3548
3548
|
value: true
|
|
3549
3549
|
}));
|
|
3550
|
-
exports.constraint = exports.state = exports.precedence = exports.
|
|
3550
|
+
exports.constraint = exports.state = exports.precedence = exports.recur = exports.recursion = exports.spend = exports.creation = void 0;
|
|
3551
3551
|
const alias_1 = __webpack_require__(5413);
|
|
3552
3552
|
function creation(cost, parser) {
|
|
3553
3553
|
return input => {
|
|
3554
3554
|
const context = input;
|
|
3555
|
-
const resources = context.resources ?? {
|
|
3556
|
-
clock: cost || 1,
|
|
3557
|
-
recursions: [1]
|
|
3558
|
-
};
|
|
3559
|
-
const {
|
|
3560
|
-
recursions
|
|
3561
|
-
} = resources;
|
|
3562
3555
|
const result = parser(input);
|
|
3563
3556
|
if (result === undefined) return;
|
|
3564
|
-
|
|
3557
|
+
spend(context, cost);
|
|
3565
3558
|
return result;
|
|
3566
3559
|
};
|
|
3567
3560
|
}
|
|
3568
3561
|
exports.creation = creation;
|
|
3569
|
-
function
|
|
3570
|
-
const {
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3562
|
+
function spend(context, cost) {
|
|
3563
|
+
const resources = context.resources ?? {
|
|
3564
|
+
clock: cost || 1,
|
|
3565
|
+
recursions: [1]
|
|
3566
|
+
};
|
|
3574
3567
|
if (resources.clock < cost) throw new Error('Too many creations');
|
|
3575
3568
|
resources.clock -= cost;
|
|
3576
3569
|
}
|
|
3577
|
-
exports.
|
|
3578
|
-
function recursion(
|
|
3570
|
+
exports.spend = spend;
|
|
3571
|
+
function recursion(index, parser) {
|
|
3579
3572
|
return input => {
|
|
3580
3573
|
const context = input;
|
|
3581
3574
|
const resources = context.resources ?? {
|
|
@@ -3585,41 +3578,19 @@ function recursion(recursion, parser) {
|
|
|
3585
3578
|
const {
|
|
3586
3579
|
recursions
|
|
3587
3580
|
} = resources;
|
|
3588
|
-
|
|
3589
|
-
if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
|
|
3590
|
-
rec >= 0 && --recursions[rec];
|
|
3581
|
+
recur(recursions, index, 1);
|
|
3591
3582
|
const result = parser(input);
|
|
3592
|
-
|
|
3583
|
+
recur(recursions, index, -1);
|
|
3593
3584
|
return result;
|
|
3594
3585
|
};
|
|
3595
3586
|
}
|
|
3596
3587
|
exports.recursion = recursion;
|
|
3597
|
-
function recursions
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
clock: 1,
|
|
3602
|
-
recursions: [4]
|
|
3603
|
-
};
|
|
3604
|
-
const {
|
|
3605
|
-
recursions
|
|
3606
|
-
} = resources;
|
|
3607
|
-
for (const recursion of rs) {
|
|
3608
|
-
const rec = (0, alias_1.min)(recursion, recursions.length - 1);
|
|
3609
|
-
if (rec === -1) continue;
|
|
3610
|
-
if (recursions[rec] < 1) throw new Error('Too much recursion');
|
|
3611
|
-
--recursions[rec];
|
|
3612
|
-
}
|
|
3613
|
-
const result = parser(input);
|
|
3614
|
-
for (const recursion of rs) {
|
|
3615
|
-
const rec = (0, alias_1.min)(recursion, recursions.length - 1);
|
|
3616
|
-
if (rec === -1) continue;
|
|
3617
|
-
++recursions[rec];
|
|
3618
|
-
}
|
|
3619
|
-
return result;
|
|
3620
|
-
};
|
|
3588
|
+
function recur(recursions, index, size, force = false) {
|
|
3589
|
+
index = (0, alias_1.min)(index, recursions.length && recursions.length - 1);
|
|
3590
|
+
if (recursions[index] < size - +force) throw new Error('Too much recursion');
|
|
3591
|
+
recursions[index] -= size;
|
|
3621
3592
|
}
|
|
3622
|
-
exports.
|
|
3593
|
+
exports.recur = recur;
|
|
3623
3594
|
function precedence(precedence, parser) {
|
|
3624
3595
|
return input => {
|
|
3625
3596
|
const context = input;
|
|
@@ -3773,7 +3744,6 @@ function some(parser, delimiter, after, delimiters, limit = 0) {
|
|
|
3773
3744
|
source,
|
|
3774
3745
|
position
|
|
3775
3746
|
} = context;
|
|
3776
|
-
//assert(context.backtracks ??= {});
|
|
3777
3747
|
let nodes;
|
|
3778
3748
|
delims && context.delimiters.push(delims);
|
|
3779
3749
|
// whileは数倍遅い
|
|
@@ -4468,7 +4438,7 @@ exports.block = error((0, combinator_1.union)([source_1.emptysegment, input => {
|
|
|
4468
4438
|
case '(':
|
|
4469
4439
|
return (0, olist_1.olist)(input);
|
|
4470
4440
|
default:
|
|
4471
|
-
if (
|
|
4441
|
+
if (char <= '9' && '0' <= char) return (0, olist_1.olist)(input);
|
|
4472
4442
|
}
|
|
4473
4443
|
}, paragraph_1.paragraph]));
|
|
4474
4444
|
function error(parser) {
|
|
@@ -4512,7 +4482,7 @@ const indent = (0, combinator_1.open)(opener, (0, combinator_1.some)(source_1.co
|
|
|
4512
4482
|
const unindent = source => source.replace(/(?<=^|\n)>(?: |(?=>*(?:$|[ \r\n])))|\r?\n$/g, '');
|
|
4513
4483
|
const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.recursion)(1 /* Recursion.blockquote */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)(autolink_1.autolink, ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('pre', (0, dom_1.defrag)((0, util_1.unwrap)(ns))))]))))]))), ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('blockquote', (0, util_1.unwrap)(ns)))])));
|
|
4514
4484
|
const markdown = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.recursion)(1 /* Recursion.blockquote */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, markdown)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, context => {
|
|
4515
|
-
(0, combinator_1.
|
|
4485
|
+
(0, combinator_1.spend)(context, 10);
|
|
4516
4486
|
const {
|
|
4517
4487
|
source
|
|
4518
4488
|
} = context;
|
|
@@ -5823,7 +5793,7 @@ exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE * 10;
|
|
|
5823
5793
|
class Context extends parser_1.Context {
|
|
5824
5794
|
constructor(options = {}) {
|
|
5825
5795
|
super(options);
|
|
5826
|
-
this.recursion = new RecursionCounter(
|
|
5796
|
+
this.recursion = new RecursionCounter(2);
|
|
5827
5797
|
const {
|
|
5828
5798
|
segment,
|
|
5829
5799
|
local,
|
|
@@ -5835,7 +5805,7 @@ class Context extends parser_1.Context {
|
|
|
5835
5805
|
id,
|
|
5836
5806
|
caches
|
|
5837
5807
|
} = options;
|
|
5838
|
-
this.resources
|
|
5808
|
+
this.resources = options.resources ?? {
|
|
5839
5809
|
// バックトラックのせいで文字数制限を受けないようにする。
|
|
5840
5810
|
clock: exports.MAX_SEGMENT_SIZE * (5 + 1),
|
|
5841
5811
|
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 */]
|
|
@@ -5853,8 +5823,7 @@ class Context extends parser_1.Context {
|
|
|
5853
5823
|
}
|
|
5854
5824
|
exports.Context = Context;
|
|
5855
5825
|
class RecursionCounter {
|
|
5856
|
-
constructor(
|
|
5857
|
-
this.syntax = syntax;
|
|
5826
|
+
constructor(limit) {
|
|
5858
5827
|
this.limit = limit;
|
|
5859
5828
|
this.stack = [];
|
|
5860
5829
|
this.index = 0;
|
|
@@ -5865,7 +5834,7 @@ class RecursionCounter {
|
|
|
5865
5834
|
} = this;
|
|
5866
5835
|
for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
|
|
5867
5836
|
// 内側から数えるので無効化処理できずエラーを投げるしかない。
|
|
5868
|
-
if (this.index === this.limit) throw new Error(`Too much
|
|
5837
|
+
if (this.index === this.limit) throw new Error(`Too much recursion`);
|
|
5869
5838
|
stack[this.index] = depth;
|
|
5870
5839
|
++this.index;
|
|
5871
5840
|
}
|
|
@@ -6067,7 +6036,7 @@ Object.defineProperty(exports, "lineshortmedia", ({
|
|
|
6067
6036
|
}
|
|
6068
6037
|
}));
|
|
6069
6038
|
function isAlphabet(char) {
|
|
6070
|
-
return
|
|
6039
|
+
return char <= 'z' && 'a' <= char;
|
|
6071
6040
|
}
|
|
6072
6041
|
|
|
6073
6042
|
/***/ },
|
|
@@ -6105,7 +6074,7 @@ const dom_1 = __webpack_require__(394);
|
|
|
6105
6074
|
// 修正する必要があるためほぼ完全な二重処理が必要になり三重以上の注釈という不適切な使用のために
|
|
6106
6075
|
// 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
|
|
6107
6076
|
const MAX_DEPTH = 20;
|
|
6108
|
-
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, repeat_1.repeat)('(', visibility_1.beforeNonblank, ')',
|
|
6077
|
+
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, repeat_1.repeat)('(', visibility_1.beforeNonblank, ')', 4 /* Recursion.bracket */, (0, combinator_1.precedence)(1, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]), ')', false, [], ([, bs], {
|
|
6109
6078
|
buffer
|
|
6110
6079
|
}) => buffer.import(bs), ([, bs], {
|
|
6111
6080
|
buffer
|
|
@@ -6519,7 +6488,7 @@ const repeat_1 = __webpack_require__(8019);
|
|
|
6519
6488
|
const visibility_1 = __webpack_require__(6364);
|
|
6520
6489
|
const util_1 = __webpack_require__(4992);
|
|
6521
6490
|
const dom_1 = __webpack_require__(394);
|
|
6522
|
-
exports.deletion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('~~', '', '~~',
|
|
6491
|
+
exports.deletion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('~~', '', '~~', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '~~')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '~'), true)])), '~~', false, [], ([, bs], {
|
|
6523
6492
|
buffer
|
|
6524
6493
|
}) => buffer.import(bs), ([, bs], {
|
|
6525
6494
|
buffer
|
|
@@ -6574,7 +6543,7 @@ const subemphasis = (0, combinator_1.lazy)(() => (0, combinator_1.some)((0, comb
|
|
|
6574
6543
|
// 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
|
|
6575
6544
|
// 可能な限り早く閉じるよう解析しなければならない。
|
|
6576
6545
|
// このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
|
|
6577
|
-
exports.emstrong = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('***', visibility_1.beforeNonblank, '***',
|
|
6546
|
+
exports.emstrong = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('***', visibility_1.beforeNonblank, '***', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank)])), (0, source_1.strs)('*', 1, 3), false, [], ([, bs, cs], context) => {
|
|
6578
6547
|
const {
|
|
6579
6548
|
buffer
|
|
6580
6549
|
} = context;
|
|
@@ -7153,7 +7122,7 @@ const repeat_1 = __webpack_require__(8019);
|
|
|
7153
7122
|
const visibility_1 = __webpack_require__(6364);
|
|
7154
7123
|
const util_1 = __webpack_require__(4992);
|
|
7155
7124
|
const dom_1 = __webpack_require__(394);
|
|
7156
|
-
exports.insertion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('++', '', '++',
|
|
7125
|
+
exports.insertion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('++', '', '++', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '++')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '+'), true)])), '++', false, [], ([, bs], {
|
|
7157
7126
|
buffer
|
|
7158
7127
|
}) => buffer.import(bs), ([, bs], {
|
|
7159
7128
|
buffer
|
|
@@ -7181,7 +7150,7 @@ const dom_1 = __webpack_require__(394);
|
|
|
7181
7150
|
// 可読性のため実際にはオブリーク体を指定する。
|
|
7182
7151
|
// 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
|
|
7183
7152
|
// ある程度の長さのある文に使うのが望ましい。
|
|
7184
|
-
exports.italic = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('///', visibility_1.beforeNonblank, '///',
|
|
7153
|
+
exports.italic = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('///', visibility_1.beforeNonblank, '///', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
|
|
7185
7154
|
buffer
|
|
7186
7155
|
}) => buffer.import(bs), ([, bs], {
|
|
7187
7156
|
buffer
|
|
@@ -7256,7 +7225,7 @@ exports.uri = (0, combinator_1.union)([(0, combinator_1.open)(' ', (0, source_1.
|
|
|
7256
7225
|
exports.option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/ nofollow(?=[ }])/y), () => new parser_1.List([new parser_1.Node(' rel="nofollow"')])), (0, source_1.str)(/ [a-z]+(?:-[a-z]+)*(?:="(?:\\[^\r\n]|[^\\\r\n"])*")?(?=[ }])/yi), (0, source_1.str)(/ [^\s{}]+/y)]);
|
|
7257
7226
|
function parse(content, params, context) {
|
|
7258
7227
|
const INSECURE_URI = params.shift().value;
|
|
7259
|
-
(0, combinator_1.
|
|
7228
|
+
(0, combinator_1.spend)(context, 10);
|
|
7260
7229
|
let uri;
|
|
7261
7230
|
try {
|
|
7262
7231
|
uri = new url_1.ReadonlyURL(resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location), context.host?.href || location.href);
|
|
@@ -7363,7 +7332,7 @@ const repeat_1 = __webpack_require__(8019);
|
|
|
7363
7332
|
const visibility_1 = __webpack_require__(6364);
|
|
7364
7333
|
const util_1 = __webpack_require__(4992);
|
|
7365
7334
|
const dom_1 = __webpack_require__(394);
|
|
7366
|
-
exports.mark = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('==', visibility_1.beforeNonblank, '==',
|
|
7335
|
+
exports.mark = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('==', visibility_1.beforeNonblank, '==', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.state)(2 /* State.mark */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '==', visibility_1.afterNonblank)), '==', false, [], ([, bs], {
|
|
7367
7336
|
buffer
|
|
7368
7337
|
}) => buffer.import(bs), ([, bs], {
|
|
7369
7338
|
buffer
|
|
@@ -7465,7 +7434,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* S
|
|
|
7465
7434
|
text = text.trim();
|
|
7466
7435
|
if (text === '' || text[0] !== tmp[0]) return;
|
|
7467
7436
|
}
|
|
7468
|
-
(0, combinator_1.
|
|
7437
|
+
(0, combinator_1.spend)(context, 100);
|
|
7469
7438
|
if (params.last.value === "\u0018" /* Command.Cancel */) {
|
|
7470
7439
|
params.pop();
|
|
7471
7440
|
return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
|
|
@@ -8157,8 +8126,9 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
8157
8126
|
exports.repeat = void 0;
|
|
8158
8127
|
const parser_1 = __webpack_require__(605);
|
|
8159
8128
|
const delimiter_1 = __webpack_require__(385);
|
|
8129
|
+
const combinator_1 = __webpack_require__(3484);
|
|
8160
8130
|
const alias_1 = __webpack_require__(5413);
|
|
8161
|
-
function repeat(opener, after, closer,
|
|
8131
|
+
function repeat(opener, after, closer, recursion, parser, cons, termination = (nodes, context, prefix, postfix) => {
|
|
8162
8132
|
const acc = new parser_1.List();
|
|
8163
8133
|
if (prefix > 0) {
|
|
8164
8134
|
acc.push(new parser_1.Node(opener[0].repeat(prefix)));
|
|
@@ -8184,7 +8154,7 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
|
|
|
8184
8154
|
position,
|
|
8185
8155
|
resources: {
|
|
8186
8156
|
recursions
|
|
8187
|
-
}
|
|
8157
|
+
}
|
|
8188
8158
|
} = context;
|
|
8189
8159
|
if (!source.startsWith(opener, context.position)) return;
|
|
8190
8160
|
let nodes = new parser_1.List();
|
|
@@ -8196,20 +8166,11 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
|
|
|
8196
8166
|
return;
|
|
8197
8167
|
}
|
|
8198
8168
|
let depth = i / opener.length + 1 | 0;
|
|
8199
|
-
|
|
8200
|
-
const rec = (0, alias_1.min)(recursion, recursions.length - 1);
|
|
8201
|
-
if (rec === -1) continue;
|
|
8202
|
-
if (recursions[rec] < depth - 1) throw new Error('Too much recursion');
|
|
8203
|
-
recursions[rec] -= depth;
|
|
8204
|
-
}
|
|
8169
|
+
(0, combinator_1.recur)(recursions, recursion, depth, true);
|
|
8205
8170
|
let state = false;
|
|
8206
8171
|
let follow = 0;
|
|
8207
8172
|
for (; i >= opener.length; i -= opener.length, follow -= closer.length) {
|
|
8208
|
-
|
|
8209
|
-
const rec = (0, alias_1.min)(recursion, recursions.length - 1);
|
|
8210
|
-
if (rec === -1) continue;
|
|
8211
|
-
recursions[rec] += 1;
|
|
8212
|
-
}
|
|
8173
|
+
(0, combinator_1.recur)(recursions, recursion, -1);
|
|
8213
8174
|
depth -= 1;
|
|
8214
8175
|
const lead = i - opener.length;
|
|
8215
8176
|
if (source.startsWith(closer, context.position)) {
|
|
@@ -8257,11 +8218,7 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
|
|
|
8257
8218
|
}
|
|
8258
8219
|
break;
|
|
8259
8220
|
}
|
|
8260
|
-
|
|
8261
|
-
const rec = (0, alias_1.min)(recursion, recursions.length - 1);
|
|
8262
|
-
if (rec === -1) continue;
|
|
8263
|
-
recursions[rec] += depth;
|
|
8264
|
-
}
|
|
8221
|
+
(0, combinator_1.recur)(recursions, recursion, -depth);
|
|
8265
8222
|
depth = 0;
|
|
8266
8223
|
const prefix = i;
|
|
8267
8224
|
i = 0;
|
|
@@ -8448,11 +8405,11 @@ const escsource = context => {
|
|
|
8448
8405
|
} = context;
|
|
8449
8406
|
if (position === source.length) return;
|
|
8450
8407
|
const char = source[position];
|
|
8451
|
-
(0, combinator_1.
|
|
8408
|
+
(0, combinator_1.spend)(context, 1);
|
|
8452
8409
|
context.position += 1;
|
|
8453
8410
|
switch (char) {
|
|
8454
8411
|
case "\u001B" /* Command.Escape */:
|
|
8455
|
-
(0, combinator_1.
|
|
8412
|
+
(0, combinator_1.spend)(context, 1);
|
|
8456
8413
|
context.position += 1;
|
|
8457
8414
|
return new parser_1.List([new parser_1.Node(source.slice(position + 1, position + 2))]);
|
|
8458
8415
|
case '\\':
|
|
@@ -8462,7 +8419,7 @@ const escsource = context => {
|
|
|
8462
8419
|
case '\n':
|
|
8463
8420
|
return new parser_1.List([new parser_1.Node(char)]);
|
|
8464
8421
|
default:
|
|
8465
|
-
(0, combinator_1.
|
|
8422
|
+
(0, combinator_1.spend)(context, 1);
|
|
8466
8423
|
context.position += 1;
|
|
8467
8424
|
return new parser_1.List([new parser_1.Node(source.slice(position, position + 2))]);
|
|
8468
8425
|
}
|
|
@@ -8475,7 +8432,7 @@ const escsource = context => {
|
|
|
8475
8432
|
if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
|
|
8476
8433
|
let i = seek(source, position);
|
|
8477
8434
|
i -= position;
|
|
8478
|
-
(0, combinator_1.
|
|
8435
|
+
(0, combinator_1.spend)(context, i - 1);
|
|
8479
8436
|
context.position += i - 1;
|
|
8480
8437
|
return new parser_1.List([new parser_1.Node(source.slice(position, context.position))]);
|
|
8481
8438
|
}
|
|
@@ -8648,7 +8605,7 @@ const text = input => {
|
|
|
8648
8605
|
} = context;
|
|
8649
8606
|
if (position === source.length) return;
|
|
8650
8607
|
const char = source[position];
|
|
8651
|
-
(0, combinator_1.
|
|
8608
|
+
(0, combinator_1.spend)(context, 1);
|
|
8652
8609
|
context.position += 1;
|
|
8653
8610
|
switch (char) {
|
|
8654
8611
|
case "\u001B" /* Command.Escape */:
|
|
@@ -8660,7 +8617,7 @@ const text = input => {
|
|
|
8660
8617
|
case '\n':
|
|
8661
8618
|
return new parser_1.List();
|
|
8662
8619
|
default:
|
|
8663
|
-
(0, combinator_1.
|
|
8620
|
+
(0, combinator_1.spend)(context, 1);
|
|
8664
8621
|
context.position += 1;
|
|
8665
8622
|
return new parser_1.List([new parser_1.Node(source.slice(position + 1, context.position))]);
|
|
8666
8623
|
}
|
|
@@ -8677,7 +8634,7 @@ const text = input => {
|
|
|
8677
8634
|
const lineend = false || s && i === source.length || s && source[i] === '\r' || s && source[i] === '\n';
|
|
8678
8635
|
i -= position;
|
|
8679
8636
|
i = lineend ? i : i - +s || 1;
|
|
8680
|
-
(0, combinator_1.
|
|
8637
|
+
(0, combinator_1.spend)(context, i - 1);
|
|
8681
8638
|
context.position += i - 1;
|
|
8682
8639
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
8683
8640
|
if (position === context.position || s && !linestart || lineend) return new parser_1.List();
|
|
@@ -8707,7 +8664,7 @@ function isWhitespace(char, linebreak) {
|
|
|
8707
8664
|
}
|
|
8708
8665
|
function next(source, position, state) {
|
|
8709
8666
|
let index = seek(source, position, state);
|
|
8710
|
-
if (index === source.length) return
|
|
8667
|
+
if (index === source.length) return index;
|
|
8711
8668
|
const char = source[index];
|
|
8712
8669
|
switch (char) {
|
|
8713
8670
|
case '%':
|
|
@@ -8771,8 +8728,9 @@ function backToEmailHead(source, position, index) {
|
|
|
8771
8728
|
}
|
|
8772
8729
|
exports.backToEmailHead = backToEmailHead;
|
|
8773
8730
|
function isAlphanumeric(char) {
|
|
8774
|
-
if (char < '0' || '
|
|
8775
|
-
|
|
8731
|
+
if (char < '0' || 'z' < char) return false;
|
|
8732
|
+
if (char <= '9' || 'a' <= char) return true;
|
|
8733
|
+
return 'A' <= char && char <= 'Z';
|
|
8776
8734
|
}
|
|
8777
8735
|
exports.isAlphanumeric = isAlphanumeric;
|
|
8778
8736
|
function seek(source, position, state) {
|
|
@@ -8878,11 +8836,11 @@ const unescsource = context => {
|
|
|
8878
8836
|
} = context;
|
|
8879
8837
|
if (position === source.length) return;
|
|
8880
8838
|
const char = source[position];
|
|
8881
|
-
(0, combinator_1.
|
|
8839
|
+
(0, combinator_1.spend)(context, 1);
|
|
8882
8840
|
context.position += 1;
|
|
8883
8841
|
switch (char) {
|
|
8884
8842
|
case "\u001B" /* Command.Escape */:
|
|
8885
|
-
(0, combinator_1.
|
|
8843
|
+
(0, combinator_1.spend)(context, 1);
|
|
8886
8844
|
context.position += 1;
|
|
8887
8845
|
return new parser_1.List([new parser_1.Node(source.slice(position + 1, position + 2))]);
|
|
8888
8846
|
case '\r':
|
|
@@ -8895,7 +8853,7 @@ const unescsource = context => {
|
|
|
8895
8853
|
text_1.nonWhitespace.lastIndex = position + 1;
|
|
8896
8854
|
let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length : next(source, position, state);
|
|
8897
8855
|
i -= position;
|
|
8898
|
-
(0, combinator_1.
|
|
8856
|
+
(0, combinator_1.spend)(context, i - 1);
|
|
8899
8857
|
context.position += i - 1;
|
|
8900
8858
|
return new parser_1.List([new parser_1.Node(source.slice(position, context.position))]);
|
|
8901
8859
|
}
|
|
@@ -8903,7 +8861,7 @@ const unescsource = context => {
|
|
|
8903
8861
|
exports.unescsource = unescsource;
|
|
8904
8862
|
function next(source, position, state) {
|
|
8905
8863
|
let index = seek(source, position, state);
|
|
8906
|
-
if (index === source.length) return
|
|
8864
|
+
if (index === source.length) return index;
|
|
8907
8865
|
const char = source[index];
|
|
8908
8866
|
switch (char) {
|
|
8909
8867
|
case ':':
|
|
@@ -8972,7 +8930,7 @@ function seek(source, position, state) {
|
|
|
8972
8930
|
return source.length;
|
|
8973
8931
|
}
|
|
8974
8932
|
function category(char) {
|
|
8975
|
-
return '\
|
|
8933
|
+
return char <= '\x7E' && '\x21' <= char;
|
|
8976
8934
|
}
|
|
8977
8935
|
|
|
8978
8936
|
/***/ },
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Parser, List, Node, Context, failsafe } from '../../data/parser';
|
|
2
|
-
import {
|
|
2
|
+
import { spend } from '../../../combinator';
|
|
3
3
|
import { firstline, isEmptyline } from '../constraint/line';
|
|
4
4
|
import { push } from 'spica/array';
|
|
5
5
|
|
|
@@ -13,7 +13,7 @@ export function fence<C extends Context, D extends Parser<unknown, C>[]>(opener:
|
|
|
13
13
|
const matches = opener.exec(source);
|
|
14
14
|
if (!matches) return;
|
|
15
15
|
assert(matches[0] === firstline(source, position));
|
|
16
|
-
|
|
16
|
+
spend(context, matches[0].length);
|
|
17
17
|
const delim = matches[1];
|
|
18
18
|
assert(delim && delim === delim.trim());
|
|
19
19
|
if (matches[0].includes(delim, delim.length)) return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Parser } from '../../data/parser';
|
|
2
|
-
import {
|
|
2
|
+
import { spend } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
export function match<P extends Parser>(pattern: RegExp, f: (matched: RegExpMatchArray) => P): P;
|
|
5
5
|
export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<N>): Parser<N> {
|
|
@@ -15,7 +15,7 @@ export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Pars
|
|
|
15
15
|
const params = pattern.exec(source);
|
|
16
16
|
if (!params) return;
|
|
17
17
|
assert(source.startsWith(params[0], position));
|
|
18
|
-
count &&
|
|
18
|
+
count && spend(context, params[0].length);
|
|
19
19
|
const result = f(params)(input);
|
|
20
20
|
context.position += result
|
|
21
21
|
? context.position === position
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Parser, Input, List, Node, Context } from './parser';
|
|
2
|
-
import {
|
|
2
|
+
import { spend } from './parser/context';
|
|
3
3
|
|
|
4
4
|
interface Delimiter {
|
|
5
5
|
readonly memory: Delimiter[];
|
|
@@ -199,7 +199,7 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
|
|
|
199
199
|
pos = position;
|
|
200
200
|
if (index === -1) return;
|
|
201
201
|
const src = source.slice(position, index);
|
|
202
|
-
count && !hit &&
|
|
202
|
+
count && !hit && spend(context, src.length);
|
|
203
203
|
if (advance) {
|
|
204
204
|
context.position = index;
|
|
205
205
|
}
|
|
@@ -250,7 +250,7 @@ export function tester(pattern: string | RegExp, advance: boolean, after?: Parse
|
|
|
250
250
|
pos = position;
|
|
251
251
|
if (index === -1) return;
|
|
252
252
|
const len = index - position;
|
|
253
|
-
count && !hit &&
|
|
253
|
+
count && !hit && spend(context, len);
|
|
254
254
|
if (advance) {
|
|
255
255
|
context.position = index;
|
|
256
256
|
}
|
|
@@ -6,61 +6,35 @@ export function creation(cost: number, parser: Parser): Parser {
|
|
|
6
6
|
assert(cost >= 0);
|
|
7
7
|
return input => {
|
|
8
8
|
const context = input;
|
|
9
|
-
const resources = context.resources ?? { clock: cost || 1, recursions: [1] };
|
|
10
|
-
const { recursions } = resources;
|
|
11
|
-
assert(recursions.length > 0);
|
|
12
9
|
const result = parser(input);
|
|
13
10
|
if (result === undefined) return;
|
|
14
|
-
|
|
11
|
+
spend(context, cost);
|
|
15
12
|
return result;
|
|
16
13
|
};
|
|
17
14
|
}
|
|
18
|
-
export function
|
|
19
|
-
const
|
|
20
|
-
if (!resources) return;
|
|
15
|
+
export function spend(context: Context, cost: number): void {
|
|
16
|
+
const resources = context.resources ?? { clock: cost || 1, recursions: [1] };
|
|
21
17
|
if (resources.clock < cost) throw new Error('Too many creations');
|
|
22
18
|
resources.clock -= cost;
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
export function recursion<P extends Parser>(
|
|
26
|
-
export function recursion(
|
|
27
|
-
assert(
|
|
21
|
+
export function recursion<P extends Parser>(index: number, parser: P): P;
|
|
22
|
+
export function recursion(index: number, parser: Parser): Parser {
|
|
23
|
+
assert(index >= 0);
|
|
28
24
|
return input => {
|
|
29
25
|
const context = input;
|
|
30
26
|
const resources = context.resources ?? { clock: 1, recursions: [1] };
|
|
31
27
|
const { recursions } = resources;
|
|
32
|
-
|
|
33
|
-
const rec = min(recursion, recursions.length - 1);
|
|
34
|
-
if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
|
|
35
|
-
rec >= 0 && --recursions[rec];
|
|
28
|
+
recur(recursions, index, 1);
|
|
36
29
|
const result = parser(input);
|
|
37
|
-
|
|
30
|
+
recur(recursions, index, -1);
|
|
38
31
|
return result;
|
|
39
32
|
};
|
|
40
33
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return input => {
|
|
46
|
-
const context = input;
|
|
47
|
-
const resources = context.resources ?? { clock: 1, recursions: [4] };
|
|
48
|
-
const { recursions } = resources;
|
|
49
|
-
assert(recursions.length > 0);
|
|
50
|
-
for (const recursion of rs) {
|
|
51
|
-
const rec = min(recursion, recursions.length - 1);
|
|
52
|
-
if (rec === -1) continue;
|
|
53
|
-
if (recursions[rec] < 1) throw new Error('Too much recursion');
|
|
54
|
-
--recursions[rec];
|
|
55
|
-
}
|
|
56
|
-
const result = parser(input);
|
|
57
|
-
for (const recursion of rs) {
|
|
58
|
-
const rec = min(recursion, recursions.length - 1);
|
|
59
|
-
if (rec === -1) continue;
|
|
60
|
-
++recursions[rec];
|
|
61
|
-
}
|
|
62
|
-
return result;
|
|
63
|
-
};
|
|
34
|
+
export function recur(recursions: number[], index: number, size: number, force: boolean = false): void {
|
|
35
|
+
index = min(index, recursions.length && recursions.length - 1);
|
|
36
|
+
if (recursions[index] < size - +force) throw new Error('Too much recursion');
|
|
37
|
+
recursions[index] -= size;
|
|
64
38
|
}
|
|
65
39
|
|
|
66
40
|
export function precedence<P extends Parser>(precedence: number, parser: P): P;
|
|
@@ -38,7 +38,6 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
|
|
|
38
38
|
return input => {
|
|
39
39
|
const context = input;
|
|
40
40
|
const { source, position } = context;
|
|
41
|
-
//assert(context.backtracks ??= {});
|
|
42
41
|
let nodes: List<Node<N>> | undefined;
|
|
43
42
|
delims && context.delimiters.push(delims);
|
|
44
43
|
// whileは数倍遅い
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BlockquoteParser } from '../block';
|
|
2
2
|
import { Recursion } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some,
|
|
4
|
+
import { union, some, spend, recursion, block, validate, rewrite, open, convert, lazy, fmap } from '../../combinator';
|
|
5
5
|
import { autolink } from '../autolink';
|
|
6
6
|
import { contentline } from '../source';
|
|
7
7
|
import { unwrap, randomID } from '../util';
|
|
@@ -40,7 +40,7 @@ const markdown: BlockquoteParser.MarkdownParser = lazy(() => fmap(
|
|
|
40
40
|
rewrite(
|
|
41
41
|
some(contentline, opener),
|
|
42
42
|
convert(unindent, context => {
|
|
43
|
-
|
|
43
|
+
spend(context, 10);
|
|
44
44
|
const { source } = context;
|
|
45
45
|
const references = html('ol', { class: 'references' });
|
|
46
46
|
const document = parse(source, {
|
package/src/parser/block.ts
CHANGED
package/src/parser/context.ts
CHANGED
|
@@ -20,7 +20,7 @@ export class Context extends Ctx {
|
|
|
20
20
|
id,
|
|
21
21
|
caches,
|
|
22
22
|
} = options;
|
|
23
|
-
this.resources
|
|
23
|
+
this.resources = options.resources ?? {
|
|
24
24
|
// バックトラックのせいで文字数制限を受けないようにする。
|
|
25
25
|
clock: MAX_SEGMENT_SIZE * (5 + 1),
|
|
26
26
|
recursions: [
|
|
@@ -42,7 +42,7 @@ export class Context extends Ctx {
|
|
|
42
42
|
this.id = id;
|
|
43
43
|
this.caches = caches;
|
|
44
44
|
}
|
|
45
|
-
public override readonly resources
|
|
45
|
+
public override readonly resources: {
|
|
46
46
|
clock: number;
|
|
47
47
|
recursions: number[];
|
|
48
48
|
};
|
|
@@ -50,7 +50,7 @@ export class Context extends Ctx {
|
|
|
50
50
|
public local: boolean;
|
|
51
51
|
public sequential: boolean;
|
|
52
52
|
public buffer: List<Node<(string | HTMLElement)>>;
|
|
53
|
-
public recursion = new RecursionCounter(
|
|
53
|
+
public recursion = new RecursionCounter(2);
|
|
54
54
|
public readonly header: boolean;
|
|
55
55
|
public readonly host?: URL;
|
|
56
56
|
public readonly url?: URL;
|
|
@@ -65,7 +65,6 @@ export type Options = Partial<Context>;
|
|
|
65
65
|
|
|
66
66
|
class RecursionCounter {
|
|
67
67
|
constructor(
|
|
68
|
-
private readonly syntax: string,
|
|
69
68
|
private readonly limit: number,
|
|
70
69
|
) {
|
|
71
70
|
}
|
|
@@ -75,7 +74,7 @@ class RecursionCounter {
|
|
|
75
74
|
const { stack } = this
|
|
76
75
|
for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
|
|
77
76
|
// 内側から数えるので無効化処理できずエラーを投げるしかない。
|
|
78
|
-
if (this.index === this.limit) throw new Error(`Too much
|
|
77
|
+
if (this.index === this.limit) throw new Error(`Too much recursion`);
|
|
79
78
|
stack[this.index] = depth;
|
|
80
79
|
++this.index;
|
|
81
80
|
}
|
|
@@ -25,7 +25,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
25
25
|
// 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
|
|
26
26
|
const MAX_DEPTH = 20;
|
|
27
27
|
export const annotation: AnnotationParser = lazy(() => constraint(State.annotation,
|
|
28
|
-
repeat('(', beforeNonblank, ')',
|
|
28
|
+
repeat('(', beforeNonblank, ')', Recursion.bracket, precedence(1, surround(
|
|
29
29
|
'',
|
|
30
30
|
some(union([inline]), ')', [[')', 1]]),
|
|
31
31
|
')',
|
|
@@ -9,7 +9,7 @@ import { unwrap } from '../util';
|
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const deletion: DeletionParser = lazy(() =>
|
|
12
|
-
repeat('~~', '', '~~',
|
|
12
|
+
repeat('~~', '', '~~', Recursion.inline, precedence(0, surround(
|
|
13
13
|
'',
|
|
14
14
|
some(union([
|
|
15
15
|
some(inline, blankWith('\n', '~~')),
|
|
@@ -24,7 +24,7 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
|
|
|
24
24
|
// 可能な限り早く閉じるよう解析しなければならない。
|
|
25
25
|
// このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
|
|
26
26
|
export const emstrong: EmStrongParser = lazy(() =>
|
|
27
|
-
repeat('***', beforeNonblank, '***',
|
|
27
|
+
repeat('***', beforeNonblank, '***', Recursion.inline, precedence(0, surround(
|
|
28
28
|
'',
|
|
29
29
|
some(union([some(inline, '*', afterNonblank)])),
|
|
30
30
|
strs('*', 1, 3),
|
|
@@ -9,7 +9,7 @@ import { unwrap } from '../util';
|
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const insertion: InsertionParser = lazy(() =>
|
|
12
|
-
repeat('++', '', '++',
|
|
12
|
+
repeat('++', '', '++', Recursion.inline, precedence(0, surround(
|
|
13
13
|
'',
|
|
14
14
|
some(union([
|
|
15
15
|
some(inline, blankWith('\n', '++')),
|
|
@@ -12,7 +12,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
12
12
|
// 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
|
|
13
13
|
// ある程度の長さのある文に使うのが望ましい。
|
|
14
14
|
export const italic: ItalicParser = lazy(() =>
|
|
15
|
-
repeat('///', beforeNonblank, '///',
|
|
15
|
+
repeat('///', beforeNonblank, '///', Recursion.inline, precedence(0, surround(
|
|
16
16
|
'',
|
|
17
17
|
some(union([inline]), '///', afterNonblank),
|
|
18
18
|
'///',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LinkParser } from '../inline';
|
|
2
2
|
import { Context, State, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, inits, sequence, subsequence, some,
|
|
4
|
+
import { union, inits, sequence, subsequence, some, spend, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { str } from '../source';
|
|
@@ -109,7 +109,7 @@ export function parse(
|
|
|
109
109
|
const INSECURE_URI = params.shift()!.value;
|
|
110
110
|
assert(INSECURE_URI === INSECURE_URI.trim());
|
|
111
111
|
assert(!INSECURE_URI.match(/\s/));
|
|
112
|
-
|
|
112
|
+
spend(context, 10);
|
|
113
113
|
let uri: ReadonlyURL | undefined;
|
|
114
114
|
try{
|
|
115
115
|
uri = new ReadonlyURL(
|
|
@@ -10,7 +10,7 @@ import { unwrap } from '../util';
|
|
|
10
10
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const mark: MarkParser = lazy(() =>
|
|
13
|
-
repeat('==', beforeNonblank, '==',
|
|
13
|
+
repeat('==', beforeNonblank, '==', Recursion.inline, precedence(0, surround(
|
|
14
14
|
'',
|
|
15
15
|
state(State.mark, some(union([inline]), '==', afterNonblank)),
|
|
16
16
|
'==',
|
|
@@ -2,7 +2,7 @@ import { MediaParser } from '../inline';
|
|
|
2
2
|
import { State, Recursion, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
4
|
import { Flag } from '../node';
|
|
5
|
-
import { union, inits, tails, some,
|
|
5
|
+
import { union, inits, tails, some, spend, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
6
6
|
import { uri, option as linkoption, resolve, decode, parse } from './link';
|
|
7
7
|
import { attributes } from './html';
|
|
8
8
|
import { unsafehtmlentity } from './htmlentity';
|
|
@@ -59,7 +59,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, open(
|
|
|
59
59
|
text = text.trim();
|
|
60
60
|
if (text === '' || text[0] !== tmp[0]) return;
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
spend(context, 100);
|
|
63
63
|
if (params.last!.value === Command.Cancel) {
|
|
64
64
|
params.pop();
|
|
65
65
|
return new List([
|
package/src/parser/inline.ts
CHANGED
package/src/parser/repeat.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { Parser, Result, List, Node } from '../combinator/data/parser';
|
|
2
2
|
import { tester } from '../combinator/data/delimiter';
|
|
3
|
+
import { recur } from '../combinator';
|
|
3
4
|
import { Context, Recursion, Command } from './context';
|
|
4
5
|
import { min } from 'spica/alias';
|
|
5
6
|
|
|
6
7
|
export function repeat<P extends Parser<HTMLElement | string, Context>>(
|
|
7
|
-
opener: string, after: string | RegExp, closer: string,
|
|
8
|
+
opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: P,
|
|
8
9
|
cons: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>, lead: number, follow: number) =>
|
|
9
10
|
List<Node<Parser.Node<P>>>,
|
|
10
11
|
termination?: (acc: List<Node<Parser.Node<P>>>, context: Context, prefix: number, postfix: number, state: boolean) =>
|
|
11
12
|
Result<string | Parser.Node<P>>,
|
|
12
13
|
): P;
|
|
13
14
|
export function repeat<N extends HTMLElement | string>(
|
|
14
|
-
opener: string, after: string | RegExp, closer: string,
|
|
15
|
+
opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: Parser<N>,
|
|
15
16
|
cons: (nodes: List<Node<N>>, context: Context, lead: number, follow: number) =>
|
|
16
17
|
List<Node<N>>,
|
|
17
18
|
termination: (acc: List<Node<N>>, context: Context, prefix: number, postfix: number, state: boolean) =>
|
|
@@ -35,7 +36,7 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
35
36
|
const test = tester(after, false);
|
|
36
37
|
return input => {
|
|
37
38
|
const context = input;
|
|
38
|
-
const { source, position, resources: { recursions }
|
|
39
|
+
const { source, position, resources: { recursions } } = context;
|
|
39
40
|
if (!source.startsWith(opener, context.position)) return;
|
|
40
41
|
let nodes = new List<Node<N>>();
|
|
41
42
|
let i = opener.length;
|
|
@@ -46,20 +47,11 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
let depth = i / opener.length + 1 | 0;
|
|
49
|
-
|
|
50
|
-
const rec = min(recursion, recursions.length - 1);
|
|
51
|
-
if (rec === -1) continue;
|
|
52
|
-
if (recursions[rec] < depth - 1) throw new Error('Too much recursion');
|
|
53
|
-
recursions[rec] -= depth;
|
|
54
|
-
}
|
|
50
|
+
recur(recursions, recursion, depth, true);
|
|
55
51
|
let state = false;
|
|
56
52
|
let follow = 0;
|
|
57
53
|
for (; i >= opener.length; i -= opener.length, follow -= closer.length) {
|
|
58
|
-
|
|
59
|
-
const rec = min(recursion, recursions.length - 1);
|
|
60
|
-
if (rec === -1) continue;
|
|
61
|
-
recursions[rec] += 1;
|
|
62
|
-
}
|
|
54
|
+
recur(recursions, recursion, -1);
|
|
63
55
|
depth -= 1;
|
|
64
56
|
const lead = i - opener.length;
|
|
65
57
|
if (source.startsWith(closer, context.position)) {
|
|
@@ -109,11 +101,7 @@ export function repeat<N extends HTMLElement | string>(
|
|
|
109
101
|
}
|
|
110
102
|
break;
|
|
111
103
|
}
|
|
112
|
-
|
|
113
|
-
const rec = min(recursion, recursions.length - 1);
|
|
114
|
-
if (rec === -1) continue;
|
|
115
|
-
recursions[rec] += depth;
|
|
116
|
-
}
|
|
104
|
+
recur(recursions, recursion, -depth);
|
|
117
105
|
depth = 0;
|
|
118
106
|
const prefix = i;
|
|
119
107
|
i = 0;
|
|
@@ -2,18 +2,18 @@ import { EscapableSourceParser } from '../source';
|
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import {
|
|
5
|
+
import { spend } from '../../combinator';
|
|
6
6
|
import { html } from 'typed-dom/dom';
|
|
7
7
|
|
|
8
8
|
export const escsource: EscapableSourceParser = context => {
|
|
9
9
|
const { source, position } = context;
|
|
10
10
|
if (position === source.length) return;
|
|
11
11
|
const char = source[position];
|
|
12
|
-
|
|
12
|
+
spend(context, 1);
|
|
13
13
|
context.position += 1;
|
|
14
14
|
switch (char) {
|
|
15
15
|
case Command.Escape:
|
|
16
|
-
|
|
16
|
+
spend(context, 1);
|
|
17
17
|
context.position += 1;
|
|
18
18
|
return new List([new Node(source.slice(position + 1, position + 2))]);
|
|
19
19
|
case '\\':
|
|
@@ -23,7 +23,7 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
23
23
|
case '\n':
|
|
24
24
|
return new List([new Node(char)]);
|
|
25
25
|
default:
|
|
26
|
-
|
|
26
|
+
spend(context, 1);
|
|
27
27
|
context.position += 1;
|
|
28
28
|
return new List([new Node(source.slice(position, position + 2))]);
|
|
29
29
|
}
|
|
@@ -38,7 +38,7 @@ export const escsource: EscapableSourceParser = context => {
|
|
|
38
38
|
let i = seek(source, position);
|
|
39
39
|
assert(i > position);
|
|
40
40
|
i -= position;
|
|
41
|
-
|
|
41
|
+
spend(context, i - 1);
|
|
42
42
|
context.position += i - 1;
|
|
43
43
|
return new List([new Node(source.slice(position, context.position))]);
|
|
44
44
|
}
|
|
@@ -2,7 +2,7 @@ import { TextParser, TxtParser } from '../source';
|
|
|
2
2
|
import { State, Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import { union,
|
|
5
|
+
import { union, spend } from '../../combinator';
|
|
6
6
|
import { html } from 'typed-dom/dom';
|
|
7
7
|
|
|
8
8
|
export const nonWhitespace = /[^ \t ]/g;
|
|
@@ -12,7 +12,7 @@ export const text: TextParser = input => {
|
|
|
12
12
|
const { source, position, state } = context;
|
|
13
13
|
if (position === source.length) return;
|
|
14
14
|
const char = source[position];
|
|
15
|
-
|
|
15
|
+
spend(context, 1);
|
|
16
16
|
context.position += 1;
|
|
17
17
|
switch (char) {
|
|
18
18
|
case Command.Escape:
|
|
@@ -25,7 +25,7 @@ export const text: TextParser = input => {
|
|
|
25
25
|
assert(char !== Command.Escape);
|
|
26
26
|
return new List();
|
|
27
27
|
default:
|
|
28
|
-
|
|
28
|
+
spend(context, 1);
|
|
29
29
|
context.position += 1;
|
|
30
30
|
return new List([new Node(source.slice(position + 1, context.position))]);
|
|
31
31
|
}
|
|
@@ -51,7 +51,7 @@ export const text: TextParser = input => {
|
|
|
51
51
|
|| s && source[i] === '\n';
|
|
52
52
|
i -= position;
|
|
53
53
|
i = lineend ? i : i - +s || 1;
|
|
54
|
-
|
|
54
|
+
spend(context, i - 1);
|
|
55
55
|
context.position += i - 1;
|
|
56
56
|
const linestart = position === 0 || source[position - 1] === '\n';
|
|
57
57
|
if (position === context.position || s && !linestart || lineend) return new List();
|
|
@@ -86,7 +86,7 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
|
|
|
86
86
|
function next(source: string, position: number, state: number): number {
|
|
87
87
|
let index= seek(source, position, state);
|
|
88
88
|
assert(index > position);
|
|
89
|
-
if (index === source.length) return
|
|
89
|
+
if (index === source.length) return index;
|
|
90
90
|
const char = source[index];
|
|
91
91
|
switch (char) {
|
|
92
92
|
case '%':
|
|
@@ -163,10 +163,9 @@ export function backToEmailHead(source: string, position: number, index: number)
|
|
|
163
163
|
}
|
|
164
164
|
export function isAlphanumeric(char: string): boolean {
|
|
165
165
|
assert(char.length === 1);
|
|
166
|
-
if (char < '0' || '
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|| 'a' <= char && char <= 'z';
|
|
166
|
+
if (char < '0' || 'z' < char) return false;
|
|
167
|
+
if (char <= '9' || 'a' <= char) return true;
|
|
168
|
+
return 'A' <= char && char <= 'Z';
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
function seek(source: string, position: number, state: number): number {
|
|
@@ -2,7 +2,7 @@ import { UnescapableSourceParser } from '../source';
|
|
|
2
2
|
import { State, Command } from '../context';
|
|
3
3
|
import { Flag } from '../node';
|
|
4
4
|
import { List, Node } from '../../combinator/data/parser';
|
|
5
|
-
import {
|
|
5
|
+
import { spend } from '../../combinator';
|
|
6
6
|
import { nonWhitespace, canSkip, backToUrlHead, backToEmailHead } from './text';
|
|
7
7
|
import { html } from 'typed-dom/dom';
|
|
8
8
|
|
|
@@ -10,11 +10,11 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
10
10
|
const { source, position, state } = context;
|
|
11
11
|
if (position === source.length) return;
|
|
12
12
|
const char = source[position];
|
|
13
|
-
|
|
13
|
+
spend(context, 1);
|
|
14
14
|
context.position += 1;
|
|
15
15
|
switch (char) {
|
|
16
16
|
case Command.Escape:
|
|
17
|
-
|
|
17
|
+
spend(context, 1);
|
|
18
18
|
context.position += 1;
|
|
19
19
|
return new List([new Node(source.slice(position + 1, position + 2))]);
|
|
20
20
|
case '\r':
|
|
@@ -33,7 +33,7 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
33
33
|
: next(source, position, state);
|
|
34
34
|
assert(i > position);
|
|
35
35
|
i -= position;
|
|
36
|
-
|
|
36
|
+
spend(context, i - 1);
|
|
37
37
|
context.position += i - 1;
|
|
38
38
|
return new List([new Node(source.slice(position, context.position))]);
|
|
39
39
|
}
|
|
@@ -42,7 +42,7 @@ export const unescsource: UnescapableSourceParser = context => {
|
|
|
42
42
|
function next(source: string, position: number, state: number): number {
|
|
43
43
|
let index= seek(source, position, state);
|
|
44
44
|
assert(index > position);
|
|
45
|
-
if (index === source.length) return
|
|
45
|
+
if (index === source.length) return index;
|
|
46
46
|
const char = source[index];
|
|
47
47
|
switch (char) {
|
|
48
48
|
case ':':
|
|
@@ -119,5 +119,5 @@ function seek(source: string, position: number, state: number): number {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
function category(char: string): boolean {
|
|
122
|
-
return '\
|
|
122
|
+
return char <= '\x7E' && '\x21' <= char;
|
|
123
123
|
}
|