securemark 0.258.0 → 0.258.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/index.js +52 -46
- package/package.json +1 -1
- package/src/combinator/control/manipulation/scope.ts +4 -4
- package/src/combinator/data/parser/context/memo.ts +12 -8
- package/src/combinator/data/parser/context.ts +7 -10
- package/src/combinator/data/parser/inits.ts +3 -2
- package/src/combinator/data/parser/sequence.ts +3 -2
- package/src/combinator/data/parser/subsequence.ts +3 -3
- package/src/combinator/data/parser/tails.ts +3 -3
- package/src/combinator/data/parser.ts +0 -1
- package/src/parser/api/parse.test.ts +11 -8
- package/src/parser/context.ts +6 -6
- package/src/parser/inline/annotation.test.ts +5 -5
- package/src/parser/inline/annotation.ts +1 -1
- package/src/parser/inline/link.test.ts +2 -1
- package/src/parser/inline/link.ts +10 -7
- package/src/parser/inline/media.test.ts +1 -0
- package/src/parser/inline/reference.test.ts +5 -5
- package/src/parser/inline/reference.ts +1 -1
- package/src/parser/inline/ruby.test.ts +1 -0
- package/src/parser/inline/template.ts +1 -1
- package/src/parser/inline.test.ts +2 -1
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.258.
|
|
1
|
+
/*! securemark v0.258.1 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
|
|
2
2
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
3
3
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
4
4
|
module.exports = factory(require("DOMPurify"), require("Prism"));
|
|
@@ -2543,9 +2543,9 @@ function focus(scope, parser) {
|
|
|
2543
2543
|
const src = match(source);
|
|
2544
2544
|
if (src === '') return;
|
|
2545
2545
|
const memo = context.memo;
|
|
2546
|
-
|
|
2546
|
+
memo && (memo.offset = source.length - src.length);
|
|
2547
2547
|
const result = parser(src, context);
|
|
2548
|
-
|
|
2548
|
+
memo && (memo.offset = source.length + src.length);
|
|
2549
2549
|
if (!result) return;
|
|
2550
2550
|
return (0, parser_1.exec)(result).length < src.length ? [(0, parser_1.eval)(result), (0, parser_1.exec)(result) + source.slice(src.length)] : global_1.undefined;
|
|
2551
2551
|
};
|
|
@@ -2562,9 +2562,9 @@ function rewrite(scope, parser) {
|
|
|
2562
2562
|
context.memo = memo;
|
|
2563
2563
|
if (!res1 || (0, parser_1.exec)(res1).length >= source.length) return;
|
|
2564
2564
|
const src = source.slice(0, source.length - (0, parser_1.exec)(res1).length);
|
|
2565
|
-
|
|
2565
|
+
memo && (memo.offset = source.length - src.length);
|
|
2566
2566
|
const res2 = parser(src, context);
|
|
2567
|
-
|
|
2567
|
+
memo && (memo.offset = source.length + src.length);
|
|
2568
2568
|
if (!res2) return;
|
|
2569
2569
|
return (0, parser_1.exec)(res2).length < src.length ? [(0, parser_1.eval)(res2), (0, parser_1.exec)(res2) + (0, parser_1.exec)(res1)] : global_1.undefined;
|
|
2570
2570
|
};
|
|
@@ -2851,10 +2851,8 @@ function syntax(syntax, precedence, cost, parser) {
|
|
|
2851
2851
|
|
|
2852
2852
|
return (source, context) => {
|
|
2853
2853
|
if (source === '') return;
|
|
2854
|
-
const r = context.rule ?? 0;
|
|
2855
|
-
context.rule = r | syntax;
|
|
2856
2854
|
context.backtrackable ??= ~0;
|
|
2857
|
-
context.state ??= 0;
|
|
2855
|
+
const state = context.state ??= 0;
|
|
2858
2856
|
const p = context.precedence;
|
|
2859
2857
|
context.precedence = precedence;
|
|
2860
2858
|
const {
|
|
@@ -2867,7 +2865,7 @@ function syntax(syntax, precedence, cost, parser) {
|
|
|
2867
2865
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
2868
2866
|
--resources.recursion;
|
|
2869
2867
|
const pos = source.length;
|
|
2870
|
-
const cache = context.memo?.get(pos,
|
|
2868
|
+
const cache = syntax && context.memo?.get(pos, syntax, state);
|
|
2871
2869
|
const result = cache ? [cache[0], source.slice(cache[1])] : parser(source, context);
|
|
2872
2870
|
++resources.recursion;
|
|
2873
2871
|
|
|
@@ -2877,9 +2875,9 @@ function syntax(syntax, precedence, cost, parser) {
|
|
|
2877
2875
|
}
|
|
2878
2876
|
|
|
2879
2877
|
if (syntax) {
|
|
2880
|
-
if (
|
|
2878
|
+
if (state & context.backtrackable) {
|
|
2881
2879
|
context.memo ??= new memo_1.Memo();
|
|
2882
|
-
cache ?? context.memo.set(pos,
|
|
2880
|
+
cache ?? context.memo.set(pos, syntax, state, (0, parser_1.eval)(result), source.length - (0, parser_1.exec)(result).length);
|
|
2883
2881
|
} else if (context.memo?.length >= pos) {
|
|
2884
2882
|
context.memo.clear(pos);
|
|
2885
2883
|
}
|
|
@@ -2887,7 +2885,6 @@ function syntax(syntax, precedence, cost, parser) {
|
|
|
2887
2885
|
}
|
|
2888
2886
|
|
|
2889
2887
|
context.precedence = p;
|
|
2890
|
-
context.rule = r;
|
|
2891
2888
|
return result;
|
|
2892
2889
|
};
|
|
2893
2890
|
}
|
|
@@ -3056,7 +3053,7 @@ Delimiters.matcher = (0, memoize_1.memoize)(pattern => {
|
|
|
3056
3053
|
/***/ }),
|
|
3057
3054
|
|
|
3058
3055
|
/***/ 1090:
|
|
3059
|
-
/***/ ((__unused_webpack_module, exports
|
|
3056
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
3060
3057
|
|
|
3061
3058
|
"use strict";
|
|
3062
3059
|
|
|
@@ -3066,28 +3063,33 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
3066
3063
|
}));
|
|
3067
3064
|
exports.Memo = void 0;
|
|
3068
3065
|
|
|
3069
|
-
const array_1 = __webpack_require__(8112);
|
|
3070
|
-
|
|
3071
3066
|
class Memo {
|
|
3072
3067
|
constructor() {
|
|
3073
3068
|
this.memory = [];
|
|
3069
|
+
this.offset = 0;
|
|
3074
3070
|
}
|
|
3075
3071
|
|
|
3076
3072
|
get length() {
|
|
3077
3073
|
return this.memory.length;
|
|
3078
3074
|
}
|
|
3079
3075
|
|
|
3080
|
-
get(position,
|
|
3081
|
-
|
|
3076
|
+
get(position, syntax, state) {
|
|
3077
|
+
//console.log('get', position + this.offset, syntax, state, this.memory[position + this.offset - 1]?.[`${syntax}:${state}`]);;
|
|
3078
|
+
return this.memory[position + this.offset - 1]?.[`${syntax}:${state}`];
|
|
3082
3079
|
}
|
|
3083
3080
|
|
|
3084
|
-
set(position,
|
|
3085
|
-
const record = this.memory[position - 1] ??= {};
|
|
3086
|
-
record[`${
|
|
3081
|
+
set(position, syntax, state, nodes, offset) {
|
|
3082
|
+
const record = this.memory[position + this.offset - 1] ??= {};
|
|
3083
|
+
record[`${syntax}:${state}`] = [nodes.slice(), offset]; //console.log('set', position + this.offset, syntax, state);
|
|
3087
3084
|
}
|
|
3088
3085
|
|
|
3089
3086
|
clear(position) {
|
|
3090
|
-
|
|
3087
|
+
const memory = this.memory;
|
|
3088
|
+
|
|
3089
|
+
for (let i = position + this.offset, len = memory.length; i < len; ++i) {
|
|
3090
|
+
memory.pop();
|
|
3091
|
+
} //console.log(position);
|
|
3092
|
+
|
|
3091
3093
|
}
|
|
3092
3094
|
|
|
3093
3095
|
}
|
|
@@ -3113,7 +3115,7 @@ const parser_1 = __webpack_require__(6728);
|
|
|
3113
3115
|
|
|
3114
3116
|
const array_1 = __webpack_require__(8112);
|
|
3115
3117
|
|
|
3116
|
-
function inits(parsers) {
|
|
3118
|
+
function inits(parsers, resume) {
|
|
3117
3119
|
if (parsers.length === 1) return parsers[0];
|
|
3118
3120
|
return (source, context) => {
|
|
3119
3121
|
let rest = source;
|
|
@@ -3126,6 +3128,7 @@ function inits(parsers) {
|
|
|
3126
3128
|
if (!result) break;
|
|
3127
3129
|
nodes = nodes ? (0, array_1.push)(nodes, (0, parser_1.eval)(result)) : (0, parser_1.eval)(result);
|
|
3128
3130
|
rest = (0, parser_1.exec)(result);
|
|
3131
|
+
if (resume?.((0, parser_1.eval)(result), (0, parser_1.exec)(result)) === false) break;
|
|
3129
3132
|
}
|
|
3130
3133
|
|
|
3131
3134
|
return nodes && rest.length < source.length ? [nodes, rest] : global_1.undefined;
|
|
@@ -3153,7 +3156,7 @@ const parser_1 = __webpack_require__(6728);
|
|
|
3153
3156
|
|
|
3154
3157
|
const array_1 = __webpack_require__(8112);
|
|
3155
3158
|
|
|
3156
|
-
function sequence(parsers) {
|
|
3159
|
+
function sequence(parsers, resume) {
|
|
3157
3160
|
if (parsers.length === 1) return parsers[0];
|
|
3158
3161
|
return (source, context) => {
|
|
3159
3162
|
let rest = source;
|
|
@@ -3166,6 +3169,7 @@ function sequence(parsers) {
|
|
|
3166
3169
|
if (!result) return;
|
|
3167
3170
|
nodes = nodes ? (0, array_1.push)(nodes, (0, parser_1.eval)(result)) : (0, parser_1.eval)(result);
|
|
3168
3171
|
rest = (0, parser_1.exec)(result);
|
|
3172
|
+
if (resume?.((0, parser_1.eval)(result), (0, parser_1.exec)(result)) === false) return;
|
|
3169
3173
|
}
|
|
3170
3174
|
|
|
3171
3175
|
return nodes && rest.length < source.length ? [nodes, rest] : global_1.undefined;
|
|
@@ -3251,8 +3255,8 @@ const union_1 = __webpack_require__(6366);
|
|
|
3251
3255
|
|
|
3252
3256
|
const inits_1 = __webpack_require__(2491);
|
|
3253
3257
|
|
|
3254
|
-
function subsequence(parsers) {
|
|
3255
|
-
return (0, union_1.union)(parsers.map((_, i) => i + 1 < parsers.length ? (0, inits_1.inits)([parsers[i], subsequence(parsers.slice(i + 1))]) : parsers[i]));
|
|
3258
|
+
function subsequence(parsers, resume) {
|
|
3259
|
+
return (0, union_1.union)(parsers.map((_, i) => i + 1 < parsers.length ? (0, inits_1.inits)([parsers[i], subsequence(parsers.slice(i + 1), resume)], resume) : parsers[i]));
|
|
3256
3260
|
}
|
|
3257
3261
|
|
|
3258
3262
|
exports.subsequence = subsequence;
|
|
@@ -3274,8 +3278,8 @@ const union_1 = __webpack_require__(6366);
|
|
|
3274
3278
|
|
|
3275
3279
|
const sequence_1 = __webpack_require__(2287);
|
|
3276
3280
|
|
|
3277
|
-
function tails(parsers) {
|
|
3278
|
-
return (0, union_1.union)(parsers.map((_, i) => (0, sequence_1.sequence)(parsers.slice(i))));
|
|
3281
|
+
function tails(parsers, resume) {
|
|
3282
|
+
return (0, union_1.union)(parsers.map((_, i) => (0, sequence_1.sequence)(parsers.slice(i), resume)));
|
|
3279
3283
|
}
|
|
3280
3284
|
|
|
3281
3285
|
exports.tails = tails;
|
|
@@ -5482,16 +5486,16 @@ Object.defineProperty(exports, "__esModule", ({
|
|
|
5482
5486
|
value: true
|
|
5483
5487
|
}));
|
|
5484
5488
|
exports.backtrackable = void 0;
|
|
5485
|
-
exports.backtrackable = 0 |
|
|
5486
|
-
/*
|
|
5487
|
-
|
|
|
5488
|
-
/*
|
|
5489
|
-
|
|
|
5490
|
-
/*
|
|
5491
|
-
|
|
|
5492
|
-
/*
|
|
5493
|
-
|
|
|
5494
|
-
/*
|
|
5489
|
+
exports.backtrackable = 0 | 64
|
|
5490
|
+
/* State.annotation */
|
|
5491
|
+
| 32
|
|
5492
|
+
/* State.reference */
|
|
5493
|
+
| 16
|
|
5494
|
+
/* State.index */
|
|
5495
|
+
| 4
|
|
5496
|
+
/* State.link */
|
|
5497
|
+
| 2
|
|
5498
|
+
/* State.media */
|
|
5495
5499
|
;
|
|
5496
5500
|
|
|
5497
5501
|
/***/ }),
|
|
@@ -5678,7 +5682,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('((
|
|
|
5678
5682
|
delimiters: global_1.undefined
|
|
5679
5683
|
}, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[/^\\?\n/, 9], [')', 2], ['))', 6]])), ')'))), '))', false, ([, ns], rest) => [[(0, dom_1.html)('sup', {
|
|
5680
5684
|
class: 'annotation'
|
|
5681
|
-
}, [(0, dom_1.html)('span', (0, visibility_1.trimNode)((0, dom_1.defrag)(ns)))])], rest], ([, ns, rest], next) => next[0] === ')' ? global_1.undefined : (0, link_1.optimize)('((', ns, rest)))));
|
|
5685
|
+
}, [(0, dom_1.html)('span', (0, visibility_1.trimNode)((0, dom_1.defrag)(ns)))])], rest], ([, ns, rest], next) => next[0] === ')' ? global_1.undefined : (0, link_1.optimize)('((', ns, rest, next)))));
|
|
5682
5686
|
|
|
5683
5687
|
/***/ }),
|
|
5684
5688
|
|
|
@@ -6663,10 +6667,9 @@ exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'
|
|
|
6663
6667
|
/* State.media */
|
|
6664
6668
|
| 1
|
|
6665
6669
|
/* State.autolink */
|
|
6666
|
-
, (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2]])), ']', true, global_1.undefined, ([, ns = [], rest], next) => next[0] === ']' ? global_1.undefined : optimize('[', ns, rest))]))),
|
|
6667
|
-
(0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))]), ([as, bs = []]) => bs[0] === '\r' && bs.shift() ? [as, bs] : as[0] === '\r' && as.shift() ? [[], as] : [as, []])), ([content, params], rest, context) => {
|
|
6668
|
-
if (params.length === 0) return;
|
|
6670
|
+
, (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2]])), ']', true, global_1.undefined, ([, ns = [], rest], next) => next[0] === ']' ? global_1.undefined : optimize('[', ns, rest, next))]))), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))], nodes => nodes[0][0] !== ''), ([as, bs = []]) => bs[0] === '\r' && bs.shift() ? [as, bs] : as[0] === '\r' && as.shift() ? [[], as] : [as, []])), ([content, params], rest, context) => {
|
|
6669
6671
|
if (content[0] === '') return [content, rest];
|
|
6672
|
+
if (params.length === 0) return;
|
|
6670
6673
|
if (content.length !== 0 && (0, visibility_1.trimNode)(content).length === 0) return;
|
|
6671
6674
|
if ((0, parser_1.eval)((0, combinator_1.some)(autolink_1.autolink)((0, util_1.stringify)(content), context))?.some(node => typeof node === 'object')) return;
|
|
6672
6675
|
const INSECURE_URI = params.shift();
|
|
@@ -6760,12 +6763,15 @@ function decode(uri) {
|
|
|
6760
6763
|
}
|
|
6761
6764
|
}
|
|
6762
6765
|
|
|
6763
|
-
function optimize(opener, ns, rest) {
|
|
6766
|
+
function optimize(opener, ns, rest, next) {
|
|
6767
|
+
if (next[+(next[0] === '\\')] === '\n') return;
|
|
6764
6768
|
let count = 0;
|
|
6765
6769
|
|
|
6766
6770
|
for (let i = 0; i < ns.length - 1; i += 2) {
|
|
6767
|
-
|
|
6768
|
-
|
|
6771
|
+
const fst = ns[i];
|
|
6772
|
+
const snd = ns[i + 1];
|
|
6773
|
+
if (fst !== '' || snd[0] !== opener[0]) break;
|
|
6774
|
+
count += snd.length;
|
|
6769
6775
|
}
|
|
6770
6776
|
|
|
6771
6777
|
return [['', opener[0].repeat(opener.length + count)], rest.slice(count)];
|
|
@@ -6990,7 +6996,7 @@ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[['
|
|
|
6990
6996
|
/* State.media */
|
|
6991
6997
|
, (0, visibility_1.startLoose)((0, combinator_1.context)({
|
|
6992
6998
|
delimiters: global_1.undefined
|
|
6993
|
-
}, (0, combinator_1.subsequence)([abbr, (0, combinator_1.open)((0, source_1.stropt)(/^(?=\^)/), (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])), (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])])), ']'))), ']]', false, ([, ns], rest) => [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, visibility_1.trimNode)((0, dom_1.defrag)(ns)))])], rest], ([, ns, rest], next) => next[0] === ']' ? global_1.undefined : (0, link_1.optimize)('[[', ns, rest)))));
|
|
6999
|
+
}, (0, combinator_1.subsequence)([abbr, (0, combinator_1.open)((0, source_1.stropt)(/^(?=\^)/), (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])), (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])])), ']'))), ']]', false, ([, ns], rest) => [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, visibility_1.trimNode)((0, dom_1.defrag)(ns)))])], rest], ([, ns, rest], next) => next[0] === ']' ? global_1.undefined : (0, link_1.optimize)('[[', ns, rest, next)))));
|
|
6994
7000
|
const abbr = (0, combinator_1.creator)((0, combinator_1.bind)((0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]), /^\|?(?=]])|^\|[^\S\n]*/), ([source], rest) => [[(0, dom_1.html)('abbr', source)], rest.replace(visibility_1.regBlankStart, '')]));
|
|
6995
7001
|
|
|
6996
7002
|
function attributes(ns) {
|
|
@@ -7191,7 +7197,7 @@ exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.syntax)(0
|
|
|
7191
7197
|
/* Rule.none */
|
|
7192
7198
|
, 2, (0, combinator_1.surround)('{{', (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), '}}', true, ([, ns = []], rest) => [[(0, dom_1.html)('span', {
|
|
7193
7199
|
class: 'template'
|
|
7194
|
-
}, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest], ([, ns = [], rest], next) => next[0] === '}' ? global_1.undefined : (0, link_1.optimize)('{{', ns, rest))));
|
|
7200
|
+
}, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest], ([, ns = [], rest], next) => next[0] === '}' ? global_1.undefined : (0, link_1.optimize)('{{', ns, rest, next))));
|
|
7195
7201
|
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')'), (0, source_1.str)(')'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']'), (0, source_1.str)(']'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), (0, source_1.str)('}'), true, global_1.undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(8, (0, combinator_1.some)(source_1.escsource, /^"|^\\?\n/)), (0, source_1.str)('"'), true)])));
|
|
7196
7202
|
|
|
7197
7203
|
/***/ }),
|
package/package.json
CHANGED
|
@@ -14,10 +14,10 @@ export function focus<T>(scope: string | RegExp, parser: Parser<T>): Parser<T> {
|
|
|
14
14
|
assert(source.startsWith(src));
|
|
15
15
|
if (src === '') return;
|
|
16
16
|
const memo = context.memo;
|
|
17
|
-
|
|
17
|
+
memo && (memo.offset = source.length - src.length);
|
|
18
18
|
const result = parser(src, context);
|
|
19
19
|
assert(check(src, result));
|
|
20
|
-
|
|
20
|
+
memo && (memo.offset = source.length + src.length);
|
|
21
21
|
if (!result) return;
|
|
22
22
|
assert(exec(result).length < src.length);
|
|
23
23
|
return exec(result).length < src.length
|
|
@@ -42,10 +42,10 @@ export function rewrite<T>(scope: Parser<unknown>, parser: Parser<T>): Parser<T>
|
|
|
42
42
|
const src = source.slice(0, source.length - exec(res1).length);
|
|
43
43
|
assert(src !== '');
|
|
44
44
|
assert(source.startsWith(src));
|
|
45
|
-
|
|
45
|
+
memo && (memo.offset = source.length - src.length);
|
|
46
46
|
const res2 = parser(src, context);
|
|
47
47
|
assert(check(src, res2));
|
|
48
|
-
|
|
48
|
+
memo && (memo.offset = source.length + src.length);
|
|
49
49
|
if (!res2) return;
|
|
50
50
|
assert(exec(res2) === '');
|
|
51
51
|
return exec(res2).length < src.length
|
|
@@ -1,30 +1,34 @@
|
|
|
1
|
-
import { splice } from 'spica/array';
|
|
2
|
-
|
|
3
1
|
export class Memo {
|
|
4
2
|
private memory: Record<string, readonly [any[], number]>[/* pos */] = [];
|
|
5
3
|
public get length(): number {
|
|
6
4
|
return this.memory.length;
|
|
7
5
|
}
|
|
6
|
+
public offset = 0;
|
|
8
7
|
public get(
|
|
9
8
|
position: number,
|
|
10
|
-
rule: number,
|
|
11
9
|
syntax: number,
|
|
12
10
|
state: number,
|
|
13
11
|
): readonly [any[], number] | undefined {
|
|
14
|
-
|
|
12
|
+
//console.log('get', position + this.offset, syntax, state, this.memory[position + this.offset - 1]?.[`${syntax}:${state}`]);;
|
|
13
|
+
return this.memory[position + this.offset - 1]?.[`${syntax}:${state}`];
|
|
15
14
|
}
|
|
16
15
|
public set(
|
|
17
16
|
position: number,
|
|
18
|
-
rule: number,
|
|
19
17
|
syntax: number,
|
|
20
18
|
state: number,
|
|
21
19
|
nodes: any[],
|
|
22
20
|
offset: number,
|
|
23
21
|
): void {
|
|
24
|
-
const record = this.memory[position - 1] ??= {};
|
|
25
|
-
record[`${
|
|
22
|
+
const record = this.memory[position + this.offset - 1] ??= {};
|
|
23
|
+
assert(!record[`${syntax}:${state}`]);
|
|
24
|
+
record[`${syntax}:${state}`] = [nodes.slice(), offset];
|
|
25
|
+
//console.log('set', position + this.offset, syntax, state);
|
|
26
26
|
}
|
|
27
27
|
public clear(position: number): void {
|
|
28
|
-
|
|
28
|
+
const memory = this.memory;
|
|
29
|
+
for (let i = position + this.offset, len = memory.length; i < len; ++i) {
|
|
30
|
+
memory.pop();
|
|
31
|
+
}
|
|
32
|
+
//console.log(position);
|
|
29
33
|
}
|
|
30
34
|
}
|
|
@@ -65,10 +65,8 @@ export function syntax<T>(syntax: number, precedence: number, cost: number | Par
|
|
|
65
65
|
}
|
|
66
66
|
return (source, context) => {
|
|
67
67
|
if (source === '') return;
|
|
68
|
-
const r = context.rule ?? 0;
|
|
69
|
-
context.rule = r | syntax;
|
|
70
68
|
context.backtrackable ??= ~0;
|
|
71
|
-
context.state ??= 0;
|
|
69
|
+
const state = context.state ??= 0;
|
|
72
70
|
const p = context.precedence;
|
|
73
71
|
context.precedence = precedence;
|
|
74
72
|
const { resources = { budget: 1, recursion: 1 } } = context;
|
|
@@ -76,7 +74,7 @@ export function syntax<T>(syntax: number, precedence: number, cost: number | Par
|
|
|
76
74
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
77
75
|
--resources.recursion;
|
|
78
76
|
const pos = source.length;
|
|
79
|
-
const cache = context.memo?.get(pos,
|
|
77
|
+
const cache = syntax && context.memo?.get(pos, syntax, state);
|
|
80
78
|
const result: Result<T> = cache
|
|
81
79
|
? [cache[0], source.slice(cache[1])]
|
|
82
80
|
: parser!(source, context);
|
|
@@ -86,20 +84,19 @@ export function syntax<T>(syntax: number, precedence: number, cost: number | Par
|
|
|
86
84
|
assert(cost = cost as number);
|
|
87
85
|
resources.budget -= cost;
|
|
88
86
|
}
|
|
89
|
-
if (syntax
|
|
90
|
-
if (
|
|
87
|
+
if (syntax) {
|
|
88
|
+
if (state & context.backtrackable) {
|
|
91
89
|
context.memo ??= new Memo();
|
|
92
|
-
cache ?? context.memo.set(pos,
|
|
93
|
-
assert.deepStrictEqual(cache && cache, cache && context.memo.get(pos,
|
|
90
|
+
cache ?? context.memo.set(pos, syntax, state, eval(result), source.length - exec(result).length);
|
|
91
|
+
assert.deepStrictEqual(cache && cache, cache && context.memo.get(pos, syntax, state));
|
|
94
92
|
}
|
|
95
93
|
else if (context.memo?.length! >= pos) {
|
|
96
|
-
assert(!(
|
|
94
|
+
assert(!(state & context.backtrackable));
|
|
97
95
|
context.memo!.clear(pos);
|
|
98
96
|
}
|
|
99
97
|
}
|
|
100
98
|
}
|
|
101
99
|
context.precedence = p;
|
|
102
|
-
context.rule = r;
|
|
103
100
|
return result;
|
|
104
101
|
};
|
|
105
102
|
}
|
|
@@ -2,8 +2,8 @@ import { undefined } from 'spica/global';
|
|
|
2
2
|
import { Parser, Ctx, Tree, Context, SubParsers, SubTree, eval, exec, check } from '../parser';
|
|
3
3
|
import { push } from 'spica/array';
|
|
4
4
|
|
|
5
|
-
export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function inits<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
5
|
+
export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
+
export function inits<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
if (parsers.length === 1) return parsers[0];
|
|
9
9
|
return (source, context) => {
|
|
@@ -19,6 +19,7 @@ export function inits<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
|
19
19
|
? push(nodes, eval(result))
|
|
20
20
|
: eval(result);
|
|
21
21
|
rest = exec(result);
|
|
22
|
+
if (resume?.(eval(result), exec(result)) === false) break;
|
|
22
23
|
}
|
|
23
24
|
assert(rest.length <= source.length);
|
|
24
25
|
return nodes && rest.length < source.length
|
|
@@ -2,8 +2,8 @@ import { undefined } from 'spica/global';
|
|
|
2
2
|
import { Parser, Ctx, Tree, Context, SubParsers, SubTree, eval, exec, check } from '../parser';
|
|
3
3
|
import { push } from 'spica/array';
|
|
4
4
|
|
|
5
|
-
export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function sequence<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
5
|
+
export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
+
export function sequence<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
if (parsers.length === 1) return parsers[0];
|
|
9
9
|
return (source, context) => {
|
|
@@ -19,6 +19,7 @@ export function sequence<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D
|
|
|
19
19
|
? push(nodes, eval(result))
|
|
20
20
|
: eval(result);
|
|
21
21
|
rest = exec(result);
|
|
22
|
+
if (resume?.(eval(result), exec(result)) === false) return;
|
|
22
23
|
}
|
|
23
24
|
assert(rest.length <= source.length);
|
|
24
25
|
return nodes && rest.length < source.length
|
|
@@ -2,12 +2,12 @@ import { Parser, Ctx, Tree, Context, SubParsers, SubTree } from '../parser';
|
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { inits } from './inits';
|
|
4
4
|
|
|
5
|
-
export function subsequence<P extends Parser<unknown>>(parsers: SubParsers<P>): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function subsequence<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
5
|
+
export function subsequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
+
export function subsequence<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
return union(
|
|
9
9
|
parsers.map((_, i) =>
|
|
10
10
|
i + 1 < parsers.length
|
|
11
|
-
? inits([parsers[i], subsequence(parsers.slice(i + 1))])
|
|
11
|
+
? inits([parsers[i], subsequence(parsers.slice(i + 1), resume)], resume)
|
|
12
12
|
: parsers[i]) as D);
|
|
13
13
|
}
|
|
@@ -2,7 +2,7 @@ import { Parser, Ctx, Tree, Context, SubParsers, SubTree } from '../parser';
|
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { sequence } from './sequence';
|
|
4
4
|
|
|
5
|
-
export function tails<P extends Parser<unknown>>(parsers: SubParsers<P>): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
-
export function tails<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
7
|
-
return union(parsers.map((_, i) => sequence(parsers.slice(i))) as D);
|
|
5
|
+
export function tails<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?: (nodes: SubTree<P>[], rest: string) => boolean): SubTree<P> extends Tree<P> ? P : Parser<SubTree<P>, Context<P>, SubParsers<P>>;
|
|
6
|
+
export function tails<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
|
+
return union(parsers.map((_, i) => sequence(parsers.slice(i), resume)) as D);
|
|
8
8
|
}
|
|
@@ -234,6 +234,15 @@ describe('Unit: parser/api/parse', () => {
|
|
|
234
234
|
});
|
|
235
235
|
|
|
236
236
|
it('recursion', () => {
|
|
237
|
+
assert.deepStrictEqual(
|
|
238
|
+
[...parse('{'.repeat(20)).children].map(el => el.outerHTML),
|
|
239
|
+
[`<p>${'{'.repeat(20)}</p>`]);
|
|
240
|
+
assert.deepStrictEqual(
|
|
241
|
+
[...parse('{'.repeat(21)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
242
|
+
[
|
|
243
|
+
'<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
|
|
244
|
+
`<pre class="error" translate="no">${'{'.repeat(21)}</pre>`,
|
|
245
|
+
]);
|
|
237
246
|
assert.deepStrictEqual(
|
|
238
247
|
[...parse('('.repeat(20)).children].map(el => el.outerHTML),
|
|
239
248
|
[`<p>${'('.repeat(20)}</p>`]);
|
|
@@ -253,14 +262,8 @@ describe('Unit: parser/api/parse', () => {
|
|
|
253
262
|
`<pre class="error" translate="no">${'['.repeat(21)}</pre>`,
|
|
254
263
|
]);
|
|
255
264
|
assert.deepStrictEqual(
|
|
256
|
-
[...parse('
|
|
257
|
-
[`<p>${'
|
|
258
|
-
assert.deepStrictEqual(
|
|
259
|
-
[...parse('{'.repeat(21)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
|
|
260
|
-
[
|
|
261
|
-
'<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
|
|
262
|
-
`<pre class="error" translate="no">${'{'.repeat(21)}</pre>`,
|
|
263
|
-
]);
|
|
265
|
+
[...parse('['.repeat(17) + '\na').children].map(el => el.outerHTML),
|
|
266
|
+
[`<p>${'['.repeat(17)}<br>a</p>`]);
|
|
264
267
|
});
|
|
265
268
|
|
|
266
269
|
if (!navigator.userAgent.includes('Chrome')) return;
|
package/src/parser/context.ts
CHANGED
|
@@ -14,12 +14,6 @@ export const enum Rule {
|
|
|
14
14
|
quote = 1 << 0,
|
|
15
15
|
none = 0,
|
|
16
16
|
}
|
|
17
|
-
export const backtrackable = 0
|
|
18
|
-
| Rule.annotation
|
|
19
|
-
| Rule.reference
|
|
20
|
-
| Rule.index
|
|
21
|
-
| Rule.link
|
|
22
|
-
| Rule.media;
|
|
23
17
|
|
|
24
18
|
export const enum State {
|
|
25
19
|
annotation = 1 << 6,
|
|
@@ -30,3 +24,9 @@ export const enum State {
|
|
|
30
24
|
media = 1 << 1,
|
|
31
25
|
autolink = 1 << 0,
|
|
32
26
|
}
|
|
27
|
+
export const backtrackable = 0
|
|
28
|
+
| State.annotation
|
|
29
|
+
| State.reference
|
|
30
|
+
| State.index
|
|
31
|
+
| State.link
|
|
32
|
+
| State.media;
|
|
@@ -18,11 +18,11 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('((\n))')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('((\na))')), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('((\\\na))')), undefined);
|
|
21
|
-
assert.deepStrictEqual(inspect(parser('((a\n))')),
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('((a\\\n))')),
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('((a\nb))')),
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('((a\\\nb))')),
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('((*a\nb*))')),
|
|
21
|
+
assert.deepStrictEqual(inspect(parser('((a\n))')), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser('((a\\\n))')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('((a\nb))')), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('((a\\\nb))')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('((*a\nb*))')), undefined);
|
|
26
26
|
assert.deepStrictEqual(inspect(parser('((\\))')), undefined);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser('((a)b))')), undefined);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('(((a))')), undefined);
|
|
@@ -17,4 +17,4 @@ export const annotation: AnnotationParser = lazy(() => validate('((', syntax(Rul
|
|
|
17
17
|
'))',
|
|
18
18
|
false,
|
|
19
19
|
([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNode(defrag(ns)))])], rest],
|
|
20
|
-
([, ns, rest], next) => next[0] === ')' ? undefined : optimize('((', ns, rest)))));
|
|
20
|
+
([, ns, rest], next) => next[0] === ')' ? undefined : optimize('((', ns, rest, next)))));
|
|
@@ -45,6 +45,7 @@ describe('Unit: parser/inline/link', () => {
|
|
|
45
45
|
it('invalid', () => {
|
|
46
46
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
47
47
|
assert.deepStrictEqual(inspect(parser('{}')), undefined);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('[{b}')), [['', '[', '<a href="b">b</a>'], '']);
|
|
48
49
|
assert.deepStrictEqual(inspect(parser('[]')), undefined);
|
|
49
50
|
assert.deepStrictEqual(inspect(parser('[]{}')), undefined);
|
|
50
51
|
assert.deepStrictEqual(inspect(parser('[]{ }')), undefined);
|
|
@@ -64,7 +65,7 @@ describe('Unit: parser/inline/link', () => {
|
|
|
64
65
|
assert.deepStrictEqual(inspect(parser('[\\ ]{b}')), undefined);
|
|
65
66
|
assert.deepStrictEqual(inspect(parser('[\\\n]{b}')), undefined);
|
|
66
67
|
assert.deepStrictEqual(inspect(parser('[	]{b}')), undefined);
|
|
67
|
-
assert.deepStrictEqual(inspect(parser('[[]{b}')),
|
|
68
|
+
assert.deepStrictEqual(inspect(parser('[[]{b}')), [['', '[', '<a href="b">b</a>'], '']);
|
|
68
69
|
assert.deepStrictEqual(inspect(parser('[]]{b}')), undefined);
|
|
69
70
|
assert.deepStrictEqual(inspect(parser('[a]{}')), undefined);
|
|
70
71
|
assert.deepStrictEqual(inspect(parser('[a\nb]{b}')), undefined);
|
|
@@ -31,16 +31,15 @@ export const link: LinkParser = lazy(() => validate(['[', '{'], syntax(Rule.link
|
|
|
31
31
|
']',
|
|
32
32
|
true,
|
|
33
33
|
undefined,
|
|
34
|
-
([, ns = [], rest], next) => next[0] === ']' ? undefined : optimize('[', ns, rest)),
|
|
34
|
+
([, ns = [], rest], next) => next[0] === ']' ? undefined : optimize('[', ns, rest, next)),
|
|
35
35
|
]))),
|
|
36
|
-
// 全体の失敗が確定した時も解析し予算を浪費している
|
|
37
36
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
|
|
38
|
-
]),
|
|
37
|
+
], nodes => nodes[0][0] !== ''),
|
|
39
38
|
([as, bs = []]) => bs[0] === '\r' && bs.shift() ? [as, bs] : as[0] === '\r' && as.shift() ? [[], as] : [as, []])),
|
|
40
39
|
([content, params]: [(HTMLElement | string)[], string[]], rest, context) => {
|
|
41
|
-
if (params.length === 0) return;
|
|
42
40
|
assert(content[0] !== '' || params.length === 0);
|
|
43
41
|
if (content[0] === '') return [content, rest];
|
|
42
|
+
if (params.length === 0) return;
|
|
44
43
|
assert(params.every(p => typeof p === 'string'));
|
|
45
44
|
if (content.length !== 0 && trimNode(content).length === 0) return;
|
|
46
45
|
if (eval(some(autolink)(stringify(content), context))?.some(node => typeof node === 'object')) return;
|
|
@@ -187,11 +186,15 @@ function decode(uri: string): string {
|
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
188
|
|
|
190
|
-
export function optimize(opener: string, ns: readonly (string | HTMLElement)[], rest: string): Result<string> {
|
|
189
|
+
export function optimize(opener: string, ns: readonly (string | HTMLElement)[], rest: string, next: string): Result<string> {
|
|
190
|
+
if (next[+(next[0] === '\\')] === '\n') return;
|
|
191
191
|
let count = 0;
|
|
192
192
|
for (let i = 0; i < ns.length - 1; i += 2) {
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
const fst = ns[i];
|
|
194
|
+
const snd = ns[i + 1] as string;
|
|
195
|
+
assert(typeof snd === 'string');
|
|
196
|
+
if (fst !== '' || snd[0] !== opener[0]) break;
|
|
197
|
+
count += snd.length;
|
|
195
198
|
}
|
|
196
199
|
return [['', opener[0].repeat(opener.length + count)], rest.slice(count)];
|
|
197
200
|
}
|
|
@@ -22,6 +22,7 @@ describe('Unit: parser/inline/media', () => {
|
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('{}')), undefined);
|
|
23
23
|
assert.deepStrictEqual(inspect(parser('[]')), undefined);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser('!{}')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('![{b}')), undefined);
|
|
25
26
|
assert.deepStrictEqual(inspect(parser('![]')), undefined);
|
|
26
27
|
assert.deepStrictEqual(inspect(parser('![]{}')), undefined);
|
|
27
28
|
assert.deepStrictEqual(inspect(parser('![]{ }')), undefined);
|
|
@@ -18,11 +18,11 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('[[\\\na]]')), undefined);
|
|
21
|
-
assert.deepStrictEqual(inspect(parser('[[a\n]]')),
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('[[a\\\n]]')),
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('[[a\nb]]')),
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('[[a\\\nb]]')),
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')),
|
|
21
|
+
assert.deepStrictEqual(inspect(parser('[[a\n]]')), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser('[[a\\\n]]')), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('[[a\nb]]')), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('[[a\\\nb]]')), undefined);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), undefined);
|
|
26
26
|
assert.deepStrictEqual(inspect(parser('[[\\]]')), undefined);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser('[[a]b]]')), undefined);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('[[[a]]')), undefined);
|
|
@@ -23,7 +23,7 @@ export const reference: ReferenceParser = lazy(() => validate('[[', syntax(Rule.
|
|
|
23
23
|
']]',
|
|
24
24
|
false,
|
|
25
25
|
([, ns], rest) => [[html('sup', attributes(ns), [html('span', trimNode(defrag(ns)))])], rest],
|
|
26
|
-
([, ns, rest], next) => next[0] === ']' ? undefined : optimize('[[', ns, rest)))));
|
|
26
|
+
([, ns, rest], next) => next[0] === ']' ? undefined : optimize('[[', ns, rest, next)))));
|
|
27
27
|
|
|
28
28
|
const abbr: ReferenceParser.AbbrParser = creator(bind(surround(
|
|
29
29
|
'^',
|
|
@@ -8,6 +8,7 @@ describe('Unit: parser/inline/ruby', () => {
|
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
11
|
+
assert.deepStrictEqual(inspect(parser('[(b)')), undefined);
|
|
11
12
|
assert.deepStrictEqual(inspect(parser('[]()')), undefined);
|
|
12
13
|
assert.deepStrictEqual(inspect(parser('[](b)')), undefined);
|
|
13
14
|
assert.deepStrictEqual(inspect(parser('[ ](b)')), undefined);
|
|
@@ -10,7 +10,7 @@ import { unshift } from 'spica/array';
|
|
|
10
10
|
export const template: TemplateParser = lazy(() => syntax(Rule.none, 2, surround(
|
|
11
11
|
'{{', some(union([bracket, escsource]), '}'), '}}', true,
|
|
12
12
|
([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest],
|
|
13
|
-
([, ns = [], rest], next) => next[0] === '}' ? undefined : optimize('{{', ns, rest))));
|
|
13
|
+
([, ns = [], rest], next) => next[0] === '}' ? undefined : optimize('{{', ns, rest, next))));
|
|
14
14
|
|
|
15
15
|
const bracket: TemplateParser.BracketParser = lazy(() => creator(union([
|
|
16
16
|
surround(str('('), some(union([bracket, escsource]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
@@ -159,6 +159,7 @@ describe('Unit: parser/inline', () => {
|
|
|
159
159
|
assert.deepStrictEqual(inspect(parser('[[${]]}$')), [['', '[[', '<span class="math" translate="no" data-src="${]]}$">${]]}$</span>'], '']);
|
|
160
160
|
assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference"><span>""</span></sup>'], '']);
|
|
161
161
|
assert.deepStrictEqual(inspect(parser('[[a](b)]{c}')), [['<a href="c"><ruby>a<rp>(</rp><rt>b</rt><rp>)</rp></ruby></a>'], '']);
|
|
162
|
+
assert.deepStrictEqual(inspect(parser('[[[[[[[{a}')), [['', '[[[[[[[', '<a href="a">a</a>'], '']);
|
|
162
163
|
assert.deepStrictEqual(inspect(parser('<http://host>')), [['<', '<a href="http://host" target="_blank">http://host</a>', '>'], '']);
|
|
163
164
|
assert.deepStrictEqual(inspect(parser('[~http://host')), [['', '[', '~', '<a href="http://host" target="_blank">http://host</a>'], '']);
|
|
164
165
|
assert.deepStrictEqual(inspect(parser('[~a@b')), [['', '[', '~', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
@@ -167,7 +168,7 @@ describe('Unit: parser/inline', () => {
|
|
|
167
168
|
assert.deepStrictEqual(inspect(parser('[^a@b')), [['[^', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
|
|
168
169
|
assert.deepStrictEqual(inspect(parser('[#a*b\nc*]')), [['[', '<a href="/hashtags/a" class="hashtag">#a</a>', '<em>b<br>c</em>', ']'], '']);
|
|
169
170
|
assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), [['[', '<em>a<br>b</em>', ']', '<a href="/">/</a>'], '']);
|
|
170
|
-
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['', '[
|
|
171
|
+
assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['[', '[', '<em>a<br>b</em>', ']', ']'], '']);
|
|
171
172
|
assert.deepStrictEqual(inspect(parser('"[% *"*"*')), [['"', '[%', ' ', '*', '"', '*', '"', '*'], '']);
|
|
172
173
|
assert.deepStrictEqual(inspect(parser('"[% "*"* %]')), [['"', '[%', ' ', '"', '*', '"', '*', ' ', '%', ']'], '']);
|
|
173
174
|
});
|