securemark 0.258.3 → 0.258.4
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 +89 -44
- package/markdown.d.ts +8 -10
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.ts +3 -1
- package/src/combinator/control/constraint/line.ts +6 -1
- package/src/combinator/control/manipulation/indent.ts +3 -0
- package/src/combinator/data/parser/context.test.ts +13 -13
- package/src/combinator/data/parser/context.ts +31 -12
- package/src/combinator/data/parser.ts +1 -1
- package/src/parser/autolink.test.ts +3 -2
- package/src/parser/autolink.ts +17 -1
- package/src/parser/block/paragraph.test.ts +3 -1
- package/src/parser/block/reply/quote.ts +1 -1
- package/src/parser/block/ulist.ts +2 -2
- package/src/parser/block.ts +1 -1
- package/src/parser/inline/annotation.ts +2 -2
- package/src/parser/inline/autolink/email.test.ts +3 -3
- package/src/parser/inline/autolink/url.test.ts +6 -6
- package/src/parser/inline/autolink.ts +4 -4
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/extension/label.ts +2 -2
- package/src/parser/inline/html.test.ts +1 -1
- package/src/parser/inline/html.ts +2 -2
- package/src/parser/inline/link.ts +2 -2
- package/src/parser/inline/media.ts +2 -2
- package/src/parser/inline/reference.ts +2 -2
- package/src/parser/inline/shortmedia.ts +2 -2
- package/src/parser/inline.test.ts +3 -3
- package/src/parser/source/text.test.ts +16 -1
- package/src/parser/source/text.ts +2 -2
- package/src/parser/visibility.ts +5 -5
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.258.
|
|
1
|
+
/*! securemark v0.258.4 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"));
|
|
@@ -2124,11 +2124,14 @@ const global_1 = __webpack_require__(4128);
|
|
|
2124
2124
|
|
|
2125
2125
|
const parser_1 = __webpack_require__(6728);
|
|
2126
2126
|
|
|
2127
|
+
const memo_1 = __webpack_require__(1090);
|
|
2128
|
+
|
|
2127
2129
|
const line_1 = __webpack_require__(9315);
|
|
2128
2130
|
|
|
2129
2131
|
function block(parser, separation = true) {
|
|
2130
|
-
return (source, context) => {
|
|
2132
|
+
return (source, context = {}) => {
|
|
2131
2133
|
if (source === '') return;
|
|
2134
|
+
context.memo ??= new memo_1.Memo();
|
|
2132
2135
|
const result = parser(source, context);
|
|
2133
2136
|
if (!result) return;
|
|
2134
2137
|
const rest = (0, parser_1.exec)(result);
|
|
@@ -2202,11 +2205,17 @@ const global_1 = __webpack_require__(4128);
|
|
|
2202
2205
|
|
|
2203
2206
|
const parser_1 = __webpack_require__(6728);
|
|
2204
2207
|
|
|
2208
|
+
const memo_1 = __webpack_require__(1090);
|
|
2209
|
+
|
|
2205
2210
|
function line(parser) {
|
|
2206
|
-
return (source, context) => {
|
|
2211
|
+
return (source, context = {}) => {
|
|
2207
2212
|
if (source === '') return;
|
|
2213
|
+
context.memo ??= new memo_1.Memo();
|
|
2208
2214
|
const line = firstline(source);
|
|
2215
|
+
const memo = context.memo;
|
|
2216
|
+
memo.offset += source.length - line.length;
|
|
2209
2217
|
const result = parser(line, context);
|
|
2218
|
+
memo.offset -= source.length - line.length;
|
|
2210
2219
|
if (!result) return;
|
|
2211
2220
|
return isEmpty((0, parser_1.exec)(result)) ? [(0, parser_1.eval)(result), source.slice(line.length)] : global_1.undefined;
|
|
2212
2221
|
};
|
|
@@ -2412,7 +2421,10 @@ const memoize_1 = __webpack_require__(1808);
|
|
|
2412
2421
|
function indent(opener, parser, separation = false) {
|
|
2413
2422
|
if (typeof opener === 'function') return indent(/^([ \t])\1*/, opener, parser);
|
|
2414
2423
|
return (0, bind_1.bind)((0, block_1.block)((0, match_1.match)(opener, (0, memoize_1.memoize)(([indent]) => (0, some_1.some)((0, line_1.line)((0, surround_1.open)(indent, source => [[source], '']))), ([indent]) => indent.length * 2 + +(indent[0] === ' '), [])), separation), (lines, rest, context) => {
|
|
2424
|
+
const memo = context.memo;
|
|
2425
|
+
memo && (memo.offset += rest.length);
|
|
2415
2426
|
const result = parser(trimBlockEnd(lines.join('')), context);
|
|
2427
|
+
memo && (memo.offset -= rest.length);
|
|
2416
2428
|
return result && (0, parser_1.exec)(result) === '' ? [(0, parser_1.eval)(result), rest] : global_1.undefined;
|
|
2417
2429
|
});
|
|
2418
2430
|
}
|
|
@@ -2783,7 +2795,7 @@ exports.check = check;
|
|
|
2783
2795
|
Object.defineProperty(exports, "__esModule", ({
|
|
2784
2796
|
value: true
|
|
2785
2797
|
}));
|
|
2786
|
-
exports.state = exports.guard = exports.precedence = exports.creation = exports.syntax = exports.context = exports.reset = void 0;
|
|
2798
|
+
exports.state = exports.constraint = exports.guard = exports.precedence = exports.creation = exports.syntax = exports.context = exports.reset = void 0;
|
|
2787
2799
|
|
|
2788
2800
|
const global_1 = __webpack_require__(4128);
|
|
2789
2801
|
|
|
@@ -2852,28 +2864,28 @@ function syntax(syntax, precedence, cost, parser) {
|
|
|
2852
2864
|
context.precedence = precedence;
|
|
2853
2865
|
const {
|
|
2854
2866
|
resources = {
|
|
2855
|
-
|
|
2867
|
+
clock: 1,
|
|
2856
2868
|
recursion: 1
|
|
2857
2869
|
}
|
|
2858
2870
|
} = context;
|
|
2859
|
-
if (resources.
|
|
2871
|
+
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
2860
2872
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
2861
2873
|
--resources.recursion;
|
|
2862
|
-
const
|
|
2874
|
+
const position = source.length;
|
|
2863
2875
|
const state = context.state ?? 0;
|
|
2864
|
-
const cache = syntax && memo.get(
|
|
2876
|
+
const cache = syntax && memo.get(position, syntax, state);
|
|
2865
2877
|
const result = cache ? cache.length === 0 ? global_1.undefined : [cache[0], source.slice(cache[1])] : parser(source, context);
|
|
2866
2878
|
++resources.recursion;
|
|
2867
2879
|
|
|
2868
2880
|
if (result && !cache) {
|
|
2869
|
-
resources.
|
|
2881
|
+
resources.clock -= cost;
|
|
2870
2882
|
}
|
|
2871
2883
|
|
|
2872
2884
|
if (syntax) {
|
|
2873
2885
|
if (state & context.memorable) {
|
|
2874
|
-
cache ?? memo.set(
|
|
2875
|
-
} else if (result && memo.length >=
|
|
2876
|
-
memo.clear(
|
|
2886
|
+
cache ?? memo.set(position, syntax, state, (0, parser_1.eval)(result), source.length - (0, parser_1.exec)(result, '').length);
|
|
2887
|
+
} else if (result && memo.length >= position) {
|
|
2888
|
+
memo.clear(position);
|
|
2877
2889
|
}
|
|
2878
2890
|
}
|
|
2879
2891
|
|
|
@@ -2889,18 +2901,18 @@ function creation(cost, parser) {
|
|
|
2889
2901
|
return (source, context) => {
|
|
2890
2902
|
const {
|
|
2891
2903
|
resources = {
|
|
2892
|
-
|
|
2904
|
+
clock: 1,
|
|
2893
2905
|
recursion: 1
|
|
2894
2906
|
}
|
|
2895
2907
|
} = context;
|
|
2896
|
-
if (resources.
|
|
2908
|
+
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
2897
2909
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
2898
2910
|
--resources.recursion;
|
|
2899
2911
|
const result = parser(source, context);
|
|
2900
2912
|
++resources.recursion;
|
|
2901
2913
|
|
|
2902
2914
|
if (result) {
|
|
2903
|
-
resources.
|
|
2915
|
+
resources.clock -= cost;
|
|
2904
2916
|
}
|
|
2905
2917
|
|
|
2906
2918
|
return result;
|
|
@@ -2927,6 +2939,20 @@ function guard(f, parser) {
|
|
|
2927
2939
|
|
|
2928
2940
|
exports.guard = guard;
|
|
2929
2941
|
|
|
2942
|
+
function constraint(state, positive, parser) {
|
|
2943
|
+
if (typeof positive === 'function') {
|
|
2944
|
+
parser = positive;
|
|
2945
|
+
positive = true;
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
return (source, context) => {
|
|
2949
|
+
const s = positive ? state & context.state : state & ~context.state;
|
|
2950
|
+
return s === state ? parser(source, context) : global_1.undefined;
|
|
2951
|
+
};
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
exports.constraint = constraint;
|
|
2955
|
+
|
|
2930
2956
|
function state(state, positive, parser) {
|
|
2931
2957
|
if (typeof positive === 'function') {
|
|
2932
2958
|
parser = positive;
|
|
@@ -3860,7 +3886,26 @@ const autolink_1 = __webpack_require__(6051);
|
|
|
3860
3886
|
|
|
3861
3887
|
const source_1 = __webpack_require__(6743);
|
|
3862
3888
|
|
|
3863
|
-
|
|
3889
|
+
const delimiter = /[@#>0-9A-Za-z\n]|\S[#>]/;
|
|
3890
|
+
|
|
3891
|
+
const autolink = (source, context) => {
|
|
3892
|
+
if (source === '') return;
|
|
3893
|
+
const i = source.search(delimiter);
|
|
3894
|
+
|
|
3895
|
+
switch (i) {
|
|
3896
|
+
case -1:
|
|
3897
|
+
return [[source], ''];
|
|
3898
|
+
|
|
3899
|
+
case 0:
|
|
3900
|
+
return parser(source, context);
|
|
3901
|
+
|
|
3902
|
+
default:
|
|
3903
|
+
return [[source.slice(0, i)], source.slice(i)];
|
|
3904
|
+
}
|
|
3905
|
+
};
|
|
3906
|
+
|
|
3907
|
+
exports.autolink = autolink;
|
|
3908
|
+
const parser = (0, combinator_1.lazy)(() => (0, combinator_1.union)([autolink_1.autolink, source_1.linebreak, source_1.unescsource]));
|
|
3864
3909
|
|
|
3865
3910
|
/***/ }),
|
|
3866
3911
|
|
|
@@ -3915,7 +3960,7 @@ const random_1 = __webpack_require__(7325);
|
|
|
3915
3960
|
|
|
3916
3961
|
exports.block = (0, combinator_1.creation)(error((0, combinator_1.reset)({
|
|
3917
3962
|
resources: {
|
|
3918
|
-
|
|
3963
|
+
clock: 50 * 1000,
|
|
3919
3964
|
recursion: 20
|
|
3920
3965
|
}
|
|
3921
3966
|
}, (0, combinator_1.union)([source_1.emptyline, horizontalrule_1.horizontalrule, heading_1.heading, ulist_1.ulist, olist_1.olist, ilist_1.ilist, dlist_1.dlist, table_1.table, codeblock_1.codeblock, mathblock_1.mathblock, extension_1.extension, sidefence_1.sidefence, blockquote_1.blockquote, reply_1.reply, paragraph_1.paragraph]))));
|
|
@@ -5315,7 +5360,7 @@ const qblock = (source, context) => {
|
|
|
5315
5360
|
}
|
|
5316
5361
|
|
|
5317
5362
|
if (child.classList.contains('cite') || child.classList.contains('quote')) {
|
|
5318
|
-
context.resources && (context.resources.
|
|
5363
|
+
context.resources && (context.resources.clock -= child.childNodes.length);
|
|
5319
5364
|
nodes.splice(i, 1, ...child.childNodes);
|
|
5320
5365
|
--i;
|
|
5321
5366
|
continue;
|
|
@@ -5450,9 +5495,9 @@ exports.ulist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combina
|
|
|
5450
5495
|
/* State.media */
|
|
5451
5496
|
, exports.ulist_))));
|
|
5452
5497
|
exports.ulist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)(/^-(?=$|\s)/, (0, combinator_1.some)((0, combinator_1.creation)((0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(/^-(?:$|\s)/, (0, combinator_1.subsequence)([exports.checkbox, (0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline])))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([exports.ulist_, olist_1.olist_, ilist_1.ilist_]))]), olist_1.invalid), ns => [(0, dom_1.html)('li', (0, dom_1.defrag)(fillFirstLine(ns)))]), true)])))), es => [format((0, dom_1.html)('ul', es))])));
|
|
5453
|
-
exports.checkbox = (0, combinator_1.focus)(/^\[[xX ]\](?=$|\s)/, source => [[(0, dom_1.html)('span', {
|
|
5498
|
+
exports.checkbox = (0, combinator_1.creation)((0, combinator_1.focus)(/^\[[xX ]\](?=$|\s)/, source => [[(0, dom_1.html)('span', {
|
|
5454
5499
|
class: 'checkbox'
|
|
5455
|
-
}, source[1].trimStart() ? '☑' : '☐')], '']);
|
|
5500
|
+
}, source[1].trimStart() ? '☑' : '☐')], '']));
|
|
5456
5501
|
|
|
5457
5502
|
function fillFirstLine(ns) {
|
|
5458
5503
|
return ns.length === 1 && typeof ns[0] === 'object' && ['UL', 'OL'].includes(ns[0].tagName) ? (0, array_1.unshift)([(0, dom_1.html)('br')], ns) : ns;
|
|
@@ -5664,9 +5709,9 @@ const visibility_1 = __webpack_require__(7618);
|
|
|
5664
5709
|
|
|
5665
5710
|
const dom_1 = __webpack_require__(3252);
|
|
5666
5711
|
|
|
5667
|
-
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('((', (0, combinator_1.
|
|
5712
|
+
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('((', (0, combinator_1.constraint)(64
|
|
5668
5713
|
/* State.annotation */
|
|
5669
|
-
, (0, combinator_1.syntax)(32
|
|
5714
|
+
, false, (0, combinator_1.syntax)(32
|
|
5670
5715
|
/* Syntax.annotation */
|
|
5671
5716
|
, 6, 1, (0, combinator_1.state)(64
|
|
5672
5717
|
/* State.annotation */
|
|
@@ -5711,12 +5756,12 @@ const source_1 = __webpack_require__(6743);
|
|
|
5711
5756
|
|
|
5712
5757
|
const util_1 = __webpack_require__(9437);
|
|
5713
5758
|
|
|
5714
|
-
exports.autolink = (0, combinator_1.fmap)((0, combinator_1.validate)(/^(?:[@#>0-9A-Za-z]|\S
|
|
5759
|
+
exports.autolink = (0, combinator_1.fmap)((0, combinator_1.validate)(/^(?:[@#>0-9A-Za-z]|\S[#>])/, (0, combinator_1.constraint)(1
|
|
5715
5760
|
/* State.autolink */
|
|
5716
|
-
, (0, combinator_1.syntax)(2
|
|
5761
|
+
, false, (0, combinator_1.syntax)(2
|
|
5717
5762
|
/* Syntax.autolink */
|
|
5718
5763
|
, 1, 1, (0, combinator_1.some)((0, combinator_1.union)([url_1.url, email_1.email, // Escape unmatched email-like strings.
|
|
5719
|
-
(0, source_1.str)(/^[0-9A-Za-z]+(?:[.+_-][0-9A-Za-z]+)*(?:@(?:[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?)
|
|
5764
|
+
(0, source_1.str)(/^[0-9A-Za-z]+(?:[.+_-][0-9A-Za-z]+)*(?:@(?:[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?)*/), channel_1.channel, account_1.account, // Escape unmatched account-like strings.
|
|
5720
5765
|
(0, source_1.str)(/^@+[0-9A-Za-z]*(?:-[0-9A-Za-z]+)*/), // Escape invalid leading characters.
|
|
5721
5766
|
(0, source_1.str)(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])(?=#)/u.source.replace('emoji', hashtag_1.emoji), 'u')), hashtag_1.hashtag, hashnum_1.hashnum, // Escape unmatched hashtag-like strings.
|
|
5722
5767
|
(0, source_1.str)(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|['_])*/u.source.replace('emoji', hashtag_1.emoji), 'u')), anchor_1.anchor]))))), ns => ns.length === 1 ? ns : [(0, util_1.stringify)(ns)]);
|
|
@@ -6216,9 +6261,9 @@ const visibility_1 = __webpack_require__(7618);
|
|
|
6216
6261
|
|
|
6217
6262
|
const dom_1 = __webpack_require__(3252);
|
|
6218
6263
|
|
|
6219
|
-
exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.
|
|
6264
|
+
exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.constraint)(16
|
|
6220
6265
|
/* State.index */
|
|
6221
|
-
, (0, combinator_1.syntax)(1024
|
|
6266
|
+
, false, (0, combinator_1.syntax)(1024
|
|
6222
6267
|
/* Syntax.index */
|
|
6223
6268
|
, 2, 1, (0, combinator_1.state)(64
|
|
6224
6269
|
/* State.annotation */
|
|
@@ -6377,9 +6422,9 @@ const dom_1 = __webpack_require__(3252);
|
|
|
6377
6422
|
|
|
6378
6423
|
const body = (0, source_1.str)(/^\$[A-Za-z]*(?:(?:-[A-Za-z][0-9A-Za-z]*)+|-(?:(?:0|[1-9][0-9]*)\.)*(?:0|[1-9][0-9]*)(?![0-9A-Za-z]))/);
|
|
6379
6424
|
exports.segment = (0, combinator_1.clear)((0, combinator_1.validate)(['[$', '$'], (0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body])));
|
|
6380
|
-
exports.label = (0, combinator_1.validate)(['[$', '$'], (0, combinator_1.creation)((0, combinator_1.fmap)((0, combinator_1.
|
|
6425
|
+
exports.label = (0, combinator_1.validate)(['[$', '$'], (0, combinator_1.creation)((0, combinator_1.fmap)((0, combinator_1.constraint)(8
|
|
6381
6426
|
/* State.label */
|
|
6382
|
-
, (0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body])), ([text]) => [(0, dom_1.html)('a', {
|
|
6427
|
+
, false, (0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body])), ([text]) => [(0, dom_1.html)('a', {
|
|
6383
6428
|
class: 'label',
|
|
6384
6429
|
'data-label': text.slice(text[1] === '-' ? 0 : 1).toLowerCase()
|
|
6385
6430
|
}, text)])));
|
|
@@ -6485,7 +6530,7 @@ global_1.Object.setPrototypeOf(attrspecs, null);
|
|
|
6485
6530
|
global_1.Object.values(attrspecs).forEach(o => global_1.Object.setPrototypeOf(o, null));
|
|
6486
6531
|
exports.html = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('<', (0, combinator_1.validate)(/^<[a-z]+(?=[^\S\n]|>)/, (0, combinator_1.syntax)(0
|
|
6487
6532
|
/* Syntax.none */
|
|
6488
|
-
, 5, 1, (0, combinator_1.union)([(0, combinator_1.focus)(
|
|
6533
|
+
, 5, 1, (0, combinator_1.union)([(0, combinator_1.focus)(/^<wbr[^\S\n]*>/, () => [[(0, dom_1.html)('wbr')], '']), (0, combinator_1.focus)( // https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
6489
6534
|
/^<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[^\S\n]|>)/, source => [[source], '']), (0, combinator_1.match)(new RegExp(String.raw`^<(${TAGS.join('|')})(?=[^\S\n]|>)`), (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true), (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)((0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', `</${tag}>`), [[(0, visibility_1.blankWith)('\n', `</${tag}>`), 5]]), true))]), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => TAGS.indexOf(tag), [])), (0, combinator_1.match)(/^<([a-z]+)(?=[^\S\n]|>)/, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true), (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)(inline_1.inline, `</${tag}>`, [[`</${tag}>`, 5]])]), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => tag, new cache_1.Cache(10000)))])))));
|
|
6490
6535
|
exports.attribute = (0, combinator_1.union)([(0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/)]); // https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
|
6491
6536
|
// [...document.querySelectorAll('tbody > tr > td:first-child')].map(el => el.textContent.slice(1, -1))
|
|
@@ -6643,9 +6688,9 @@ const optspec = {
|
|
|
6643
6688
|
rel: ['nofollow']
|
|
6644
6689
|
};
|
|
6645
6690
|
Object.setPrototypeOf(optspec, null);
|
|
6646
|
-
exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'], (0, combinator_1.bind)((0, combinator_1.
|
|
6691
|
+
exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'], (0, combinator_1.bind)((0, combinator_1.constraint)(4
|
|
6647
6692
|
/* State.link */
|
|
6648
|
-
, (0, combinator_1.syntax)(256
|
|
6693
|
+
, false, (0, combinator_1.syntax)(256
|
|
6649
6694
|
/* Syntax.link */
|
|
6650
6695
|
, 2, 10, (0, combinator_1.fmap)((0, combinator_1.subsequence)([(0, combinator_1.state)(4
|
|
6651
6696
|
/* State.link */
|
|
@@ -6881,9 +6926,9 @@ const optspec = {
|
|
|
6881
6926
|
rel: global_1.undefined
|
|
6882
6927
|
};
|
|
6883
6928
|
Object.setPrototypeOf(optspec, null);
|
|
6884
|
-
exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.
|
|
6929
|
+
exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.constraint)(2
|
|
6885
6930
|
/* State.media */
|
|
6886
|
-
, (0, combinator_1.syntax)(64
|
|
6931
|
+
, false, (0, combinator_1.syntax)(64
|
|
6887
6932
|
/* Syntax.media */
|
|
6888
6933
|
, 2, 10, (0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', [[/^\\?\n/, 9]]), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))])))), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], (0, array_1.shift)(bs)[1]] : [[''], (0, array_1.shift)(as)[1]]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
|
|
6889
6934
|
const INSECURE_URI = params.shift();
|
|
@@ -6982,9 +7027,9 @@ const util_1 = __webpack_require__(9437);
|
|
|
6982
7027
|
|
|
6983
7028
|
const dom_1 = __webpack_require__(3252);
|
|
6984
7029
|
|
|
6985
|
-
exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('[[', (0, combinator_1.
|
|
7030
|
+
exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('[[', (0, combinator_1.constraint)(32
|
|
6986
7031
|
/* State.reference */
|
|
6987
|
-
, (0, combinator_1.syntax)(4096
|
|
7032
|
+
, false, (0, combinator_1.syntax)(4096
|
|
6988
7033
|
/* Syntax.reference */
|
|
6989
7034
|
, 6, 1, (0, combinator_1.state)(64
|
|
6990
7035
|
/* State.annotation */
|
|
@@ -7131,9 +7176,9 @@ const url_1 = __webpack_require__(4318);
|
|
|
7131
7176
|
|
|
7132
7177
|
const media_1 = __webpack_require__(1303);
|
|
7133
7178
|
|
|
7134
|
-
exports.shortmedia = (0, combinator_1.rewrite)((0, combinator_1.
|
|
7179
|
+
exports.shortmedia = (0, combinator_1.rewrite)((0, combinator_1.constraint)(2
|
|
7135
7180
|
/* State.media */
|
|
7136
|
-
, (0, combinator_1.open)('!', url_1.url)), (0, combinator_1.convert)(source => `!{ ${source.slice(1)} }`, (0, combinator_1.union)([media_1.media])));
|
|
7181
|
+
, false, (0, combinator_1.open)('!', url_1.url)), (0, combinator_1.convert)(source => `!{ ${source.slice(1)} }`, (0, combinator_1.union)([media_1.media])));
|
|
7137
7182
|
|
|
7138
7183
|
/***/ }),
|
|
7139
7184
|
|
|
@@ -7965,9 +8010,9 @@ const str_1 = __webpack_require__(2790);
|
|
|
7965
8010
|
|
|
7966
8011
|
const dom_1 = __webpack_require__(3252);
|
|
7967
8012
|
|
|
7968
|
-
exports.delimiter = /[\s\x00-\x7F]|\S
|
|
8013
|
+
exports.delimiter = /[\s\x00-\x7F]|\S[#>]|[()、。!?][^\S\n]*(?=\\\n)/;
|
|
7969
8014
|
exports.nonWhitespace = /[\S\n]|$/;
|
|
7970
|
-
exports.nonAlphanumeric = /[^0-9A-Za-z]|\S
|
|
8015
|
+
exports.nonAlphanumeric = /[^0-9A-Za-z]|\S[#>]|$/;
|
|
7971
8016
|
const repeat = (0, str_1.str)(/^(.)\1*/);
|
|
7972
8017
|
exports.text = (0, combinator_1.creation)((source, context) => {
|
|
7973
8018
|
if (source === '') return;
|
|
@@ -8146,7 +8191,7 @@ const memoize_1 = __webpack_require__(1808);
|
|
|
8146
8191
|
const array_1 = __webpack_require__(8112);
|
|
8147
8192
|
|
|
8148
8193
|
function visualize(parser) {
|
|
8149
|
-
const blankline = new RegExp(/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr
|
|
8194
|
+
const blankline = new RegExp(/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+$/.source.replace('IHN', `(?:${normalize_1.invisibleHTMLEntityNames.join('|')})`), 'gm');
|
|
8150
8195
|
return (0, combinator_1.union)([(0, combinator_1.convert)(source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')), (0, combinator_1.verify)(parser, (ns, rest, context) => !rest && hasVisible(ns, context))), (0, combinator_1.some)((0, combinator_1.union)([source_1.linebreak, source_1.unescsource]))]);
|
|
8151
8196
|
}
|
|
8152
8197
|
|
|
@@ -8173,11 +8218,11 @@ function hasVisible(nodes, {
|
|
|
8173
8218
|
return false;
|
|
8174
8219
|
}
|
|
8175
8220
|
|
|
8176
|
-
exports.regBlankStart = new RegExp(/^(?:\\?[^\S\n]|&IHN;|<wbr
|
|
8221
|
+
exports.regBlankStart = new RegExp(/^(?:\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+/.source.replace('IHN', `(?:${normalize_1.invisibleHTMLEntityNames.join('|')})`));
|
|
8177
8222
|
|
|
8178
8223
|
function blankWith(starting, delimiter) {
|
|
8179
8224
|
if (delimiter === global_1.undefined) return blankWith('', starting);
|
|
8180
|
-
return new RegExp(String.raw`^(?:(?=${starting})(?:\\?\s|&(?:${normalize_1.invisibleHTMLEntityNames.join('|')});|<wbr
|
|
8225
|
+
return new RegExp(String.raw`^(?:(?=${starting})(?:\\?\s|&(?:${normalize_1.invisibleHTMLEntityNames.join('|')});|<wbr[^\S\n]*>)${starting && '+'})?${typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source}`);
|
|
8181
8226
|
}
|
|
8182
8227
|
|
|
8183
8228
|
exports.blankWith = blankWith;
|
|
@@ -8220,7 +8265,7 @@ const isStartTight = (0, memoize_1.reduce)((source, context, except) => {
|
|
|
8220
8265
|
|
|
8221
8266
|
case '<':
|
|
8222
8267
|
switch (true) {
|
|
8223
|
-
case source.length >= 5 && source
|
|
8268
|
+
case source.length >= 5 && source.slice(0, 4) === '<wbr' && (source[5] === '>' || /^<wbr[^\S\n]*>/.test(source)):
|
|
8224
8269
|
return false;
|
|
8225
8270
|
}
|
|
8226
8271
|
|
package/markdown.d.ts
CHANGED
|
@@ -964,7 +964,7 @@ export namespace MarkdownParser {
|
|
|
964
964
|
Inline<'html'>,
|
|
965
965
|
Parser<HTMLElement | string, Context, [
|
|
966
966
|
HTMLParser.OpenTagParser,
|
|
967
|
-
|
|
967
|
+
HTMLParser.OpenTagParser,
|
|
968
968
|
HTMLParser.TagParser,
|
|
969
969
|
HTMLParser.TagParser,
|
|
970
970
|
]> {
|
|
@@ -972,8 +972,8 @@ export namespace MarkdownParser {
|
|
|
972
972
|
export namespace HTMLParser {
|
|
973
973
|
export interface OpenTagParser extends
|
|
974
974
|
Inline<'html/opentag'>,
|
|
975
|
-
Parser<HTMLElement, Context, [
|
|
976
|
-
|
|
975
|
+
Parser<HTMLElement | string, Context, [
|
|
976
|
+
AttributeParser,
|
|
977
977
|
]> {
|
|
978
978
|
}
|
|
979
979
|
export interface TagParser extends
|
|
@@ -983,13 +983,11 @@ export namespace MarkdownParser {
|
|
|
983
983
|
InlineParser,
|
|
984
984
|
]> {
|
|
985
985
|
}
|
|
986
|
-
export
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
]> {
|
|
992
|
-
}
|
|
986
|
+
export interface AttributeParser extends
|
|
987
|
+
Inline<'html/attribute'>,
|
|
988
|
+
Parser<string, Context, [
|
|
989
|
+
SourceParser.StrParser,
|
|
990
|
+
]> {
|
|
993
991
|
}
|
|
994
992
|
}
|
|
995
993
|
export interface InsertionParser extends
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { Parser, exec } from '../../data/parser';
|
|
3
|
+
import { Memo } from '../../data/parser/context/memo';
|
|
3
4
|
import { firstline, isEmpty } from './line';
|
|
4
5
|
|
|
5
6
|
export function block<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
|
|
6
7
|
export function block<T>(parser: Parser<T>, separation = true): Parser<T> {
|
|
7
8
|
assert(parser);
|
|
8
|
-
return (source, context) => {
|
|
9
|
+
return (source, context = {}) => {
|
|
9
10
|
if (source === '') return;
|
|
11
|
+
context.memo ??= new Memo();
|
|
10
12
|
const result = parser(source, context);
|
|
11
13
|
if (!result) return;
|
|
12
14
|
const rest = exec(result);
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { Parser, eval, exec, check } from '../../data/parser';
|
|
3
|
+
import { Memo } from '../../data/parser/context/memo';
|
|
3
4
|
|
|
4
5
|
export function line<P extends Parser<unknown>>(parser: P): P;
|
|
5
6
|
export function line<T>(parser: Parser<T>): Parser<T> {
|
|
6
7
|
assert(parser);
|
|
7
|
-
return (source, context) => {
|
|
8
|
+
return (source, context = {}) => {
|
|
8
9
|
if (source === '') return;
|
|
10
|
+
context.memo ??= new Memo();
|
|
9
11
|
const line = firstline(source);
|
|
12
|
+
const memo = context.memo!;
|
|
13
|
+
memo.offset += source.length - line.length;
|
|
10
14
|
const result = parser(line, context);
|
|
11
15
|
assert(check(line, result));
|
|
16
|
+
memo.offset -= source.length - line.length;
|
|
12
17
|
if (!result) return;
|
|
13
18
|
return isEmpty(exec(result))
|
|
14
19
|
? [eval(result), source.slice(line.length)]
|
|
@@ -21,7 +21,10 @@ export function indent<T>(opener: RegExp | Parser<T>, parser?: Parser<T> | boole
|
|
|
21
21
|
([indent]) => indent.length * 2 + +(indent[0] === ' '), [])), separation),
|
|
22
22
|
(lines, rest, context) => {
|
|
23
23
|
assert(parser = parser as Parser<T>);
|
|
24
|
+
const memo = context.memo;
|
|
25
|
+
memo && (memo.offset += rest.length);
|
|
24
26
|
const result = parser(trimBlockEnd(lines.join('')), context);
|
|
27
|
+
memo && (memo.offset -= rest.length);
|
|
25
28
|
return result && exec(result) === ''
|
|
26
29
|
? [eval(result), rest]
|
|
27
30
|
: undefined;
|
|
@@ -10,27 +10,27 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
10
10
|
|
|
11
11
|
describe('reset', () => {
|
|
12
12
|
const parser: Parser<number> = some(creation(
|
|
13
|
-
(s, context) => [[context.resources?.
|
|
13
|
+
(s, context) => [[context.resources?.clock ?? NaN], s.slice(1)]));
|
|
14
14
|
|
|
15
15
|
it('root', () => {
|
|
16
|
-
const base: Context = { resources: {
|
|
16
|
+
const base: Context = { resources: { clock: 3, recursion: 1 } };
|
|
17
17
|
const ctx: Context = {};
|
|
18
18
|
assert.deepStrictEqual(reset(base, parser)('123', ctx), [[3, 2, 1], '']);
|
|
19
|
-
assert(base.resources?.
|
|
20
|
-
assert(ctx.resources?.
|
|
19
|
+
assert(base.resources?.clock === 3);
|
|
20
|
+
assert(ctx.resources?.clock === undefined);
|
|
21
21
|
assert.throws(() => reset(base, parser)('1234', ctx));
|
|
22
|
-
assert(ctx.resources?.
|
|
22
|
+
assert(ctx.resources?.clock === undefined);
|
|
23
23
|
assert.deepStrictEqual(reset(base, parser)('123', ctx), [[3, 2, 1], '']);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('node', () => {
|
|
27
|
-
const base: Context = { resources: {
|
|
28
|
-
const ctx: Context = { resources: {
|
|
27
|
+
const base: Context = { resources: { clock: 3, recursion: 1 } };
|
|
28
|
+
const ctx: Context = { resources: { clock: 1, recursion: 1 } };
|
|
29
29
|
assert.deepStrictEqual(reset(base, parser)('1', ctx), [[1], '']);
|
|
30
|
-
assert(base.resources?.
|
|
31
|
-
assert(ctx.resources?.
|
|
30
|
+
assert(base.resources?.clock === 3);
|
|
31
|
+
assert(ctx.resources?.clock === 0);
|
|
32
32
|
assert.throws(() => reset(base, parser)('1', ctx));
|
|
33
|
-
assert(ctx.resources?.
|
|
33
|
+
assert(ctx.resources?.clock === 0);
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
});
|
|
@@ -41,12 +41,12 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
41
41
|
|
|
42
42
|
it('', () => {
|
|
43
43
|
const base: Context = { status: true };
|
|
44
|
-
const ctx: Context = { resources: {
|
|
44
|
+
const ctx: Context = { resources: { clock: 3, recursion: 1 } };
|
|
45
45
|
assert.deepStrictEqual(context(base, parser)('123', ctx), [[true, true, true], '']);
|
|
46
|
-
assert(ctx.resources?.
|
|
46
|
+
assert(ctx.resources?.clock === 0);
|
|
47
47
|
assert(ctx.status === undefined);
|
|
48
48
|
assert.throws(() => reset(base, parser)('1', ctx));
|
|
49
|
-
assert(ctx.resources?.
|
|
49
|
+
assert(ctx.resources?.clock === 0);
|
|
50
50
|
assert(ctx.status === undefined);
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -64,13 +64,13 @@ export function syntax<T>(syntax: number, precedence: number, cost: number, pars
|
|
|
64
64
|
context.memorable ??= ~0;
|
|
65
65
|
const p = context.precedence;
|
|
66
66
|
context.precedence = precedence;
|
|
67
|
-
const { resources = {
|
|
68
|
-
if (resources.
|
|
67
|
+
const { resources = { clock: 1, recursion: 1 } } = context;
|
|
68
|
+
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
69
69
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
70
70
|
--resources.recursion;
|
|
71
|
-
const
|
|
71
|
+
const position = source.length;
|
|
72
72
|
const state = context.state ?? 0;
|
|
73
|
-
const cache = syntax && memo.get(
|
|
73
|
+
const cache = syntax && memo.get(position, syntax, state);
|
|
74
74
|
const result: Result<T> = cache
|
|
75
75
|
? cache.length === 0
|
|
76
76
|
? undefined
|
|
@@ -78,16 +78,16 @@ export function syntax<T>(syntax: number, precedence: number, cost: number, pars
|
|
|
78
78
|
: parser!(source, context);
|
|
79
79
|
++resources.recursion;
|
|
80
80
|
if (result && !cache) {
|
|
81
|
-
resources.
|
|
81
|
+
resources.clock -= cost;
|
|
82
82
|
}
|
|
83
83
|
if (syntax) {
|
|
84
84
|
if (state & context.memorable!) {
|
|
85
|
-
cache ?? memo.set(
|
|
86
|
-
assert.deepStrictEqual(cache && cache, cache && memo.get(
|
|
85
|
+
cache ?? memo.set(position, syntax, state, eval(result), source.length - exec(result, '').length);
|
|
86
|
+
assert.deepStrictEqual(cache && cache, cache && memo.get(position, syntax, state));
|
|
87
87
|
}
|
|
88
|
-
else if (result && memo.length! >=
|
|
88
|
+
else if (result && memo.length! >= position) {
|
|
89
89
|
assert(!(state & context.memorable!));
|
|
90
|
-
memo.clear(
|
|
90
|
+
memo.clear(position);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
context.precedence = p;
|
|
@@ -101,14 +101,14 @@ export function creation(cost: number | Parser<unknown>, parser?: Parser<unknown
|
|
|
101
101
|
if (typeof cost === 'function') return creation(1, cost);
|
|
102
102
|
assert(cost >= 0);
|
|
103
103
|
return (source, context) => {
|
|
104
|
-
const { resources = {
|
|
105
|
-
if (resources.
|
|
104
|
+
const { resources = { clock: 1, recursion: 1 } } = context;
|
|
105
|
+
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
106
106
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
107
107
|
--resources.recursion;
|
|
108
108
|
const result = parser!(source, context);
|
|
109
109
|
++resources.recursion;
|
|
110
110
|
if (result) {
|
|
111
|
-
resources.
|
|
111
|
+
resources.clock -= cost;
|
|
112
112
|
}
|
|
113
113
|
return result;
|
|
114
114
|
};
|
|
@@ -133,6 +133,24 @@ export function guard<T>(f: (context: Ctx) => boolean | number, parser: Parser<T
|
|
|
133
133
|
: undefined;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
export function constraint<P extends Parser<unknown>>(state: number, parser: P): P;
|
|
137
|
+
export function constraint<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
|
|
138
|
+
export function constraint<T>(state: number, positive: boolean | Parser<T>, parser?: Parser<T>): Parser<T> {
|
|
139
|
+
if (typeof positive === 'function') {
|
|
140
|
+
parser = positive;
|
|
141
|
+
positive = true;
|
|
142
|
+
}
|
|
143
|
+
assert(state);
|
|
144
|
+
return (source, context) => {
|
|
145
|
+
const s = positive
|
|
146
|
+
? state & context.state!
|
|
147
|
+
: state & ~context.state!;
|
|
148
|
+
return s === state
|
|
149
|
+
? parser!(source, context)
|
|
150
|
+
: undefined;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
136
154
|
export function state<P extends Parser<unknown>>(state: number, parser: P): P;
|
|
137
155
|
export function state<P extends Parser<unknown>>(state: number, positive: boolean, parser: P): P;
|
|
138
156
|
export function state<T>(state: number, positive: boolean | Parser<T>, parser?: Parser<T>): Parser<T> {
|
|
@@ -140,6 +158,7 @@ export function state<T>(state: number, positive: boolean | Parser<T>, parser?:
|
|
|
140
158
|
parser = positive;
|
|
141
159
|
positive = true;
|
|
142
160
|
}
|
|
161
|
+
assert(state);
|
|
143
162
|
return (source, context) => {
|
|
144
163
|
const s = context.state ?? 0;
|
|
145
164
|
context.state = positive
|
|
@@ -13,13 +13,14 @@ describe('Unit: parser/autolink', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('@a#b')), [['<a href="/@a?ch=b" class="channel">@a#b</a>'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '<br>'], '']);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('a#b')), [['a#b'], '']);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('0a#b')), [['
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('0a#b')), [['0a#b'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('あ#b')), [['あ#b'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('あい#b')), [['あ', 'い#b'], '']);
|
|
19
|
-
assert.deepStrictEqual(inspect(parser('0aあ#b')), [['0a
|
|
19
|
+
assert.deepStrictEqual(inspect(parser('0aあ#b')), [['0aあ#b'], '']);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('0aあい#b')), [['0a', 'あ', 'い#b'], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('a\n#b')), [['a', '<br>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('a\\\n#b')), [['a', '\\', '<br>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('0a>>b')), [['0a>>b'], '']);
|
|
23
24
|
});
|
|
24
25
|
|
|
25
26
|
});
|
package/src/parser/autolink.ts
CHANGED
|
@@ -5,7 +5,23 @@ import { linebreak, unescsource } from './source';
|
|
|
5
5
|
|
|
6
6
|
export import AutolinkParser = MarkdownParser.AutolinkParser;
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const delimiter = /[@#>0-9A-Za-z\n]|\S[#>]/;
|
|
9
|
+
|
|
10
|
+
export const autolink: AutolinkParser = (source, context) => {
|
|
11
|
+
if (source === '') return;
|
|
12
|
+
assert(source[0] !== '\x1B');
|
|
13
|
+
const i = source.search(delimiter);
|
|
14
|
+
switch (i) {
|
|
15
|
+
case -1:
|
|
16
|
+
return [[source], ''];
|
|
17
|
+
case 0:
|
|
18
|
+
return parser(source, context);
|
|
19
|
+
default:
|
|
20
|
+
return [[source.slice(0, i)], source.slice(i)];
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const parser: AutolinkParser = lazy(() => union([
|
|
9
25
|
autolink_,
|
|
10
26
|
linebreak,
|
|
11
27
|
unescsource
|
|
@@ -45,13 +45,15 @@ describe('Unit: parser/block/paragraph', () => {
|
|
|
45
45
|
assert.deepStrictEqual(inspect(parser('>>11 a')), [['<p><a href="?at=11" class="anchor">>>11</a> a</p>'], '']);
|
|
46
46
|
assert.deepStrictEqual(inspect(parser('>>>11 a')), [['<p>><a href="?at=11" class="anchor">>>11</a> a</p>'], '']);
|
|
47
47
|
assert.deepStrictEqual(inspect(parser('>> a\n>>1')), [['<p>>> a<br><a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
48
|
-
assert.deepStrictEqual(inspect(parser('a>>1')), [['<p>a
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('a>>1')), [['<p>a>>1</p>'], '']);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser('ab>>1')), [['<p>ab>>1</p>'], '']);
|
|
49
50
|
assert.deepStrictEqual(inspect(parser('a >>1')), [['<p>a <a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
50
51
|
assert.deepStrictEqual(inspect(parser('a\n>>1')), [['<p>a<br><a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
51
52
|
assert.deepStrictEqual(inspect(parser('a\n>>1\nb')), [['<p>a<br><a href="?at=1" class="anchor">>>1</a><br>b</p>'], '']);
|
|
52
53
|
assert.deepStrictEqual(inspect(parser('a\n>> b\nc')), [['<p>a<br>>> b<br>c</p>'], '']);
|
|
53
54
|
assert.deepStrictEqual(inspect(parser('\t>>1')), [['<p>\t<a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
54
55
|
assert.deepStrictEqual(inspect(parser('\t>>>1')), [['<p>\t><a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('あ>>1')), [['<p>あ<a href="?at=1" class="anchor">>>1</a></p>'], '']);
|
|
55
57
|
});
|
|
56
58
|
|
|
57
59
|
it('comment', () => {
|
|
@@ -58,7 +58,7 @@ const qblock: ReplyParser.QuoteParser.BlockParser = (source, context) => {
|
|
|
58
58
|
continue;
|
|
59
59
|
}
|
|
60
60
|
if (child.classList.contains('cite') || child.classList.contains('quote')) {
|
|
61
|
-
context.resources && (context.resources.
|
|
61
|
+
context.resources && (context.resources.clock -= child.childNodes.length);
|
|
62
62
|
nodes.splice(i, 1, ...child.childNodes as NodeListOf<HTMLElement>);
|
|
63
63
|
--i;
|
|
64
64
|
continue;
|
|
@@ -26,11 +26,11 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
|
|
|
26
26
|
])))),
|
|
27
27
|
es => [format(html('ul', es))])));
|
|
28
28
|
|
|
29
|
-
export const checkbox = focus(
|
|
29
|
+
export const checkbox = creation(focus(
|
|
30
30
|
/^\[[xX ]\](?=$|\s)/,
|
|
31
31
|
source => [[
|
|
32
32
|
html('span', { class: 'checkbox' }, source[1].trimStart() ? '☑' : '☐'),
|
|
33
|
-
], '']);
|
|
33
|
+
], '']));
|
|
34
34
|
|
|
35
35
|
export function fillFirstLine(ns: (HTMLElement | string)[]): (HTMLElement | string)[] {
|
|
36
36
|
return ns.length === 1
|
package/src/parser/block.ts
CHANGED
|
@@ -36,7 +36,7 @@ export import ReplyParser = BlockParser.ReplyParser;
|
|
|
36
36
|
export import ParagraphParser = BlockParser.ParagraphParser;
|
|
37
37
|
|
|
38
38
|
export const block: BlockParser = creation(error(
|
|
39
|
-
reset({ resources: {
|
|
39
|
+
reset({ resources: { clock: 50 * 1000, recursion: 20 } },
|
|
40
40
|
union([
|
|
41
41
|
emptyline,
|
|
42
42
|
horizontalrule,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { AnnotationParser } from '../inline';
|
|
3
|
-
import { union, some,
|
|
3
|
+
import { union, some, context, syntax, constraint, state, surround, lazy } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { optimize } from './link';
|
|
6
6
|
import { Syntax, State } from '../context';
|
|
@@ -9,7 +9,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
9
9
|
|
|
10
10
|
export const annotation: AnnotationParser = lazy(() => surround(
|
|
11
11
|
'((',
|
|
12
|
-
|
|
12
|
+
constraint(State.annotation, false,
|
|
13
13
|
syntax(Syntax.annotation, 6, 1,
|
|
14
14
|
state(State.annotation | State.media,
|
|
15
15
|
startLoose(
|
|
@@ -20,9 +20,9 @@ describe('Unit: parser/inline/autolink/email', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('a@b#1')), [['a@b#1'], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('a@@')), [['a@@'], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('a@@b')), [['a@@b'], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('a+@b')),
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('a..b@c')),
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('a++b@c')),
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('a+@b')), [['a'], '+@b']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('a..b@c')), [['a'], '..b@c']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('a++b@c')), [['a'], '++b@c']);
|
|
26
26
|
assert.deepStrictEqual(inspect(parser(`a@${'b'.repeat(64)}`)), [[`a@${'b'.repeat(64)}`], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser(' a@b')), undefined);
|
|
28
28
|
});
|
|
@@ -8,12 +8,12 @@ describe('Unit: parser/inline/autolink/url', () => {
|
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
11
|
-
assert.deepStrictEqual(inspect(parser('http')),
|
|
12
|
-
assert.deepStrictEqual(inspect(parser('ttp')),
|
|
13
|
-
assert.deepStrictEqual(inspect(parser('http://')),
|
|
14
|
-
assert.deepStrictEqual(inspect(parser('http://[')),
|
|
15
|
-
assert.deepStrictEqual(inspect(parser('http://]')),
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('Http://host')),
|
|
11
|
+
assert.deepStrictEqual(inspect(parser('http')), [['http'], '']);
|
|
12
|
+
assert.deepStrictEqual(inspect(parser('ttp')), [['ttp'], '']);
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('http://')), [['http'], '://']);
|
|
14
|
+
assert.deepStrictEqual(inspect(parser('http://[')), [['http'], '://[']);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('http://]')), [['http'], '://]']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('Http://host')), [['Http'], '://host']);
|
|
17
17
|
//assert.deepStrictEqual(inspect(parser('http://[::ffff:0:0%1]')), [['<a class="invalid">http://[::ffff:0:0%1]</a>'], '']);
|
|
18
18
|
//assert.deepStrictEqual(inspect(parser('http://[::ffff:0:0/96]')), [['<a class="invalid">http://[::ffff:0:0/96]</a>'], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser(' http://a')), undefined);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AutolinkParser } from '../inline';
|
|
2
|
-
import { union, some, syntax,
|
|
2
|
+
import { union, some, syntax, constraint, validate, fmap } from '../../combinator';
|
|
3
3
|
import { url } from './autolink/url';
|
|
4
4
|
import { email } from './autolink/email';
|
|
5
5
|
import { channel } from './autolink/channel';
|
|
@@ -12,14 +12,14 @@ import { Syntax, State } from '../context';
|
|
|
12
12
|
import { stringify } from '../util';
|
|
13
13
|
|
|
14
14
|
export const autolink: AutolinkParser = fmap(
|
|
15
|
-
validate(/^(?:[@#>0-9A-Za-z]|\S
|
|
16
|
-
|
|
15
|
+
validate(/^(?:[@#>0-9A-Za-z]|\S[#>])/,
|
|
16
|
+
constraint(State.autolink, false,
|
|
17
17
|
syntax(Syntax.autolink, 1, 1,
|
|
18
18
|
some(union([
|
|
19
19
|
url,
|
|
20
20
|
email,
|
|
21
21
|
// Escape unmatched email-like strings.
|
|
22
|
-
str(/^[0-9A-Za-z]+(?:[.+_-][0-9A-Za-z]+)*(?:@(?:[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?)
|
|
22
|
+
str(/^[0-9A-Za-z]+(?:[.+_-][0-9A-Za-z]+)*(?:@(?:[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?)*/),
|
|
23
23
|
channel,
|
|
24
24
|
account,
|
|
25
25
|
// Escape unmatched account-like strings.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { ExtensionParser } from '../../inline';
|
|
3
|
-
import { union, some, syntax, creation, precedence,
|
|
3
|
+
import { union, some, syntax, creation, precedence, constraint, state, validate, surround, open, lazy, fmap } from '../../../combinator';
|
|
4
4
|
import { inline } from '../../inline';
|
|
5
5
|
import { indexee, identity } from './indexee';
|
|
6
6
|
import { txt, str, stropt } from '../../source';
|
|
@@ -12,7 +12,7 @@ import IndexParser = ExtensionParser.IndexParser;
|
|
|
12
12
|
|
|
13
13
|
export const index: IndexParser = lazy(() => validate('[#', fmap(indexee(surround(
|
|
14
14
|
'[#',
|
|
15
|
-
|
|
15
|
+
constraint(State.index, false,
|
|
16
16
|
syntax(Syntax.index, 2, 1,
|
|
17
17
|
state(State.annotation | State.reference | State.index | State.label | State.link | State.media | State.autolink,
|
|
18
18
|
startTight(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Array } from 'spica/global';
|
|
2
2
|
import { ExtensionParser } from '../../inline';
|
|
3
|
-
import { union,
|
|
3
|
+
import { union, constraint, creation, validate, surround, clear, fmap } from '../../../combinator';
|
|
4
4
|
import { str } from '../../source';
|
|
5
5
|
import { State } from '../../context';
|
|
6
6
|
import { html } from 'typed-dom/dom';
|
|
@@ -13,7 +13,7 @@ export const segment: ExtensionParser.LabelParser.SegmentParser = clear(validate
|
|
|
13
13
|
])));
|
|
14
14
|
|
|
15
15
|
export const label: ExtensionParser.LabelParser = validate(['[$', '$'], creation(fmap(
|
|
16
|
-
|
|
16
|
+
constraint(State.label, false,
|
|
17
17
|
union([
|
|
18
18
|
surround('[', body, ']'),
|
|
19
19
|
body,
|
|
@@ -122,7 +122,7 @@ describe('Unit: parser/inline/html', () => {
|
|
|
122
122
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
123
123
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
124
124
|
assert.deepStrictEqual(inspect(parser('<wbr\n>')), undefined);
|
|
125
|
-
assert.deepStrictEqual(inspect(parser('<wbr >')), [['<wbr'], '
|
|
125
|
+
assert.deepStrictEqual(inspect(parser('<wbr >')), [['<wbr>'], '']);
|
|
126
126
|
assert.deepStrictEqual(inspect(parser('<wbr constructor>')), [['<wbr'], ' constructor>']);
|
|
127
127
|
assert.deepStrictEqual(inspect(parser('<wbr X>')), [['<wbr'], ' X>']);
|
|
128
128
|
assert.deepStrictEqual(inspect(parser('<wbr x>')), [['<wbr'], ' x>']);
|
|
@@ -21,7 +21,7 @@ Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
|
|
|
21
21
|
|
|
22
22
|
export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/, syntax(Syntax.none, 5, 1, union([
|
|
23
23
|
focus(
|
|
24
|
-
|
|
24
|
+
/^<wbr[^\S\n]*>/,
|
|
25
25
|
() => [[h('wbr')], '']),
|
|
26
26
|
focus(
|
|
27
27
|
// https://html.spec.whatwg.org/multipage/syntax.html#void-elements
|
|
@@ -62,7 +62,7 @@ export const html: HTMLParser = lazy(() => validate('<', validate(/^<[a-z]+(?=[^
|
|
|
62
62
|
new Cache(10000))),
|
|
63
63
|
])))));
|
|
64
64
|
|
|
65
|
-
export const attribute: HTMLParser.
|
|
65
|
+
export const attribute: HTMLParser.AttributeParser = union([
|
|
66
66
|
str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/),
|
|
67
67
|
]);
|
|
68
68
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { undefined, location, encodeURI, decodeURI, Location } from 'spica/global';
|
|
2
2
|
import { LinkParser, TextLinkParser } from '../inline';
|
|
3
3
|
import { Result, eval, exec } from '../../combinator/data/parser';
|
|
4
|
-
import { union, inits, tails, subsequence, some,
|
|
4
|
+
import { union, inits, tails, subsequence, some, constraint, syntax, creation, precedence, state, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { autolink } from '../autolink';
|
|
@@ -18,7 +18,7 @@ const optspec = {
|
|
|
18
18
|
Object.setPrototypeOf(optspec, null);
|
|
19
19
|
|
|
20
20
|
export const link: LinkParser = lazy(() => validate(['[', '{'], bind(
|
|
21
|
-
|
|
21
|
+
constraint(State.link, false,
|
|
22
22
|
syntax(Syntax.link, 2, 10,
|
|
23
23
|
fmap(subsequence([
|
|
24
24
|
state(State.link,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { undefined, location } from 'spica/global';
|
|
2
2
|
import { MediaParser } from '../inline';
|
|
3
|
-
import { union, inits, tails, some, creation, precedence,
|
|
3
|
+
import { union, inits, tails, some, syntax, creation, precedence, constraint, validate, verify, surround, open, dup, lazy, fmap, bind } from '../../combinator';
|
|
4
4
|
import { textlink, uri, option as linkoption, resolve } from './link';
|
|
5
5
|
import { attributes } from './html';
|
|
6
6
|
import { unsafehtmlentity } from './htmlentity';
|
|
@@ -20,7 +20,7 @@ Object.setPrototypeOf(optspec, null);
|
|
|
20
20
|
|
|
21
21
|
export const media: MediaParser = lazy(() => validate(['![', '!{'], bind(verify(fmap(open(
|
|
22
22
|
'!',
|
|
23
|
-
|
|
23
|
+
constraint(State.media, false,
|
|
24
24
|
syntax(Syntax.media, 2, 10,
|
|
25
25
|
tails([
|
|
26
26
|
dup(surround(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
2
|
import { ReferenceParser } from '../inline';
|
|
3
|
-
import { union, subsequence, some, context,
|
|
3
|
+
import { union, subsequence, some, context, syntax, creation, constraint, state, surround, open, lazy, bind } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { optimize } from './link';
|
|
6
6
|
import { str, stropt } from '../source';
|
|
@@ -11,7 +11,7 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
11
11
|
|
|
12
12
|
export const reference: ReferenceParser = lazy(() => surround(
|
|
13
13
|
'[[',
|
|
14
|
-
|
|
14
|
+
constraint(State.reference, false,
|
|
15
15
|
syntax(Syntax.reference, 6, 1,
|
|
16
16
|
state(State.annotation | State.reference | State.media,
|
|
17
17
|
startLoose(
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ShortmediaParser } from '../inline';
|
|
2
|
-
import { union,
|
|
2
|
+
import { union, constraint, rewrite, open, convert } from '../../combinator';
|
|
3
3
|
import { url } from './autolink/url';
|
|
4
4
|
import { media } from './media';
|
|
5
5
|
import { State } from '../context';
|
|
6
6
|
|
|
7
7
|
export const shortmedia: ShortmediaParser = rewrite(
|
|
8
|
-
|
|
8
|
+
constraint(State.media, false,
|
|
9
9
|
open('!', url)),
|
|
10
10
|
convert(
|
|
11
11
|
source => `!{ ${source.slice(1)} }`,
|
|
@@ -110,7 +110,7 @@ describe('Unit: parser/inline', () => {
|
|
|
110
110
|
assert.deepStrictEqual(inspect(parser('[@a]')), [['[', '<a href="/@a" class="account">@a</a>', ']'], '']);
|
|
111
111
|
assert.deepStrictEqual(inspect(parser('[#1][#2]')), [['<a class="index" href="#index:1">1</a>', '<a class="index" href="#index:2">2</a>'], '']);
|
|
112
112
|
assert.deepStrictEqual(inspect(parser('[$1]')), [['[', '$', '1', ']'], '']);
|
|
113
|
-
assert.deepStrictEqual(inspect(parser('[$1-2]')), [['[', '$', '1
|
|
113
|
+
assert.deepStrictEqual(inspect(parser('[$1-2]')), [['[', '$', '1-2', ']'], '']);
|
|
114
114
|
assert.deepStrictEqual(inspect(parser('[$-1][$-2]')), [['<a class="label" data-label="$-1">$-1</a>', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
115
115
|
assert.deepStrictEqual(inspect(parser('$-1, $-2')), [['<a class="label" data-label="$-1">$-1</a>', ',', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
116
116
|
assert.deepStrictEqual(inspect(parser('$-1 and $-2')), [['<a class="label" data-label="$-1">$-1</a>', ' ', 'and', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
@@ -225,10 +225,10 @@ describe('Unit: parser/inline', () => {
|
|
|
225
225
|
assert.deepStrictEqual(inspect(parser('#a\nb\n#c\n[#d]')), [['<a href="/hashtags/a" class="hashtag">#a</a>', '<br>', 'b', '<br>', '<a href="/hashtags/c" class="hashtag">#c</a>', '<br>', '<a class="index" href="#index:d">d</a>'], '']);
|
|
226
226
|
assert.deepStrictEqual(inspect(parser('##a')), [['##a'], '']);
|
|
227
227
|
assert.deepStrictEqual(inspect(parser('a#b')), [['a#b'], '']);
|
|
228
|
-
assert.deepStrictEqual(inspect(parser('0a#b')), [['
|
|
228
|
+
assert.deepStrictEqual(inspect(parser('0a#b')), [['0a#b'], '']);
|
|
229
229
|
assert.deepStrictEqual(inspect(parser('あ#b')), [['あ#b'], '']);
|
|
230
230
|
assert.deepStrictEqual(inspect(parser('あい#b')), [['あ', 'い#b'], '']);
|
|
231
|
-
assert.deepStrictEqual(inspect(parser('0aあ#b')), [['0a
|
|
231
|
+
assert.deepStrictEqual(inspect(parser('0aあ#b')), [['0aあ#b'], '']);
|
|
232
232
|
assert.deepStrictEqual(inspect(parser('0aあい#b')), [['0a', 'あ', 'い#b'], '']);
|
|
233
233
|
assert.deepStrictEqual(inspect(parser('「#あ」')), [['「', '<a href="/hashtags/あ" class="hashtag">#あ</a>', '」'], '']);
|
|
234
234
|
assert.deepStrictEqual(inspect(parser('a\n#b')), [['a', '<br>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
@@ -82,7 +82,7 @@ describe('Unit: parser/text/text', () => {
|
|
|
82
82
|
assert.deepStrictEqual(inspect(parser('0@0')), [['0', '@', '0'], '']);
|
|
83
83
|
assert.deepStrictEqual(inspect(parser('a@0')), [['a', '@', '0'], '']);
|
|
84
84
|
assert.deepStrictEqual(inspect(parser('A@0')), [['A', '@', '0'], '']);
|
|
85
|
-
assert.deepStrictEqual(inspect(parser('
|
|
85
|
+
assert.deepStrictEqual(inspect(parser('aA@0')), [['aA', '@', '0'], '']);
|
|
86
86
|
assert.deepStrictEqual(inspect(parser(' @0')), [[' ', '@', '0'], '']);
|
|
87
87
|
assert.deepStrictEqual(inspect(parser('@@0')), [['@', '@', '0'], '']);
|
|
88
88
|
});
|
|
@@ -96,10 +96,25 @@ describe('Unit: parser/text/text', () => {
|
|
|
96
96
|
assert.deepStrictEqual(inspect(parser('0#0')), [['0', '#', '0'], '']);
|
|
97
97
|
assert.deepStrictEqual(inspect(parser('a#0')), [['a', '#', '0'], '']);
|
|
98
98
|
assert.deepStrictEqual(inspect(parser('A#0')), [['A', '#', '0'], '']);
|
|
99
|
+
assert.deepStrictEqual(inspect(parser('aA#0')), [['a', 'A', '#', '0'], '']);
|
|
99
100
|
assert.deepStrictEqual(inspect(parser(' #0')), [[' ', '#', '0'], '']);
|
|
100
101
|
assert.deepStrictEqual(inspect(parser('##0')), [['#', '#', '0'], '']);
|
|
101
102
|
});
|
|
102
103
|
|
|
104
|
+
it('anchor', () => {
|
|
105
|
+
assert.deepStrictEqual(inspect(parser('>>0')), [['>', '>', '0'], '']);
|
|
106
|
+
assert.deepStrictEqual(inspect(parser('_>>0')), [['_', '>', '>', '0'], '']);
|
|
107
|
+
assert.deepStrictEqual(inspect(parser('$>>0')), [['$', '>', '>', '0'], '']);
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('+>>0')), [['+', '>', '>', '0'], '']);
|
|
109
|
+
assert.deepStrictEqual(inspect(parser('->>0')), [['-', '>', '>', '0'], '']);
|
|
110
|
+
assert.deepStrictEqual(inspect(parser('0>>0')), [['0', '>', '>', '0'], '']);
|
|
111
|
+
assert.deepStrictEqual(inspect(parser('a>>0')), [['a', '>', '>', '0'], '']);
|
|
112
|
+
assert.deepStrictEqual(inspect(parser('A>>0')), [['A', '>', '>', '0'], '']);
|
|
113
|
+
assert.deepStrictEqual(inspect(parser('aA>>0')), [['a', 'A', '>', '>', '0'], '']);
|
|
114
|
+
assert.deepStrictEqual(inspect(parser(' >>0')), [[' ', '>', '>', '0'], '']);
|
|
115
|
+
assert.deepStrictEqual(inspect(parser('>>>>0')), [['>', '>', '>', '>', '0'], '']);
|
|
116
|
+
});
|
|
117
|
+
|
|
103
118
|
it('localize', () => {
|
|
104
119
|
assert.deepStrictEqual(inspect(parser('.\\\n0')), [['.', '<span class="linebreak"> </span>', '0'], '']);
|
|
105
120
|
assert.deepStrictEqual(inspect(parser('。\\\n0')), [['。', '<span class="linebreak"></span>', '0'], '']);
|
|
@@ -4,9 +4,9 @@ import { union, creation, focus } from '../../combinator';
|
|
|
4
4
|
import { str } from './str';
|
|
5
5
|
import { html } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
|
-
export const delimiter = /[\s\x00-\x7F]|\S
|
|
7
|
+
export const delimiter = /[\s\x00-\x7F]|\S[#>]|[()、。!?][^\S\n]*(?=\\\n)/;
|
|
8
8
|
export const nonWhitespace = /[\S\n]|$/;
|
|
9
|
-
export const nonAlphanumeric = /[^0-9A-Za-z]|\S
|
|
9
|
+
export const nonAlphanumeric = /[^0-9A-Za-z]|\S[#>]|$/;
|
|
10
10
|
const repeat = str(/^(.)\1*/);
|
|
11
11
|
|
|
12
12
|
export const text: TextParser = creation((source, context) => {
|
package/src/parser/visibility.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { push } from 'spica/array';
|
|
|
12
12
|
export function visualize<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
13
13
|
export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
14
14
|
const blankline = new RegExp(
|
|
15
|
-
/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr
|
|
15
|
+
/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+$/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
16
16
|
'gm');
|
|
17
17
|
return union([
|
|
18
18
|
convert(
|
|
@@ -40,7 +40,7 @@ function hasVisible(
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export const regBlankStart = new RegExp(
|
|
43
|
-
/^(?:\\?[^\S\n]|&IHN;|<wbr
|
|
43
|
+
/^(?:\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`));
|
|
44
44
|
|
|
45
45
|
export function blankWith(delimiter: string | RegExp): RegExp;
|
|
46
46
|
export function blankWith(starting: '' | '\n', delimiter: string | RegExp): RegExp;
|
|
@@ -49,7 +49,7 @@ export function blankWith(starting: '' | '\n', delimiter?: string | RegExp): Reg
|
|
|
49
49
|
return new RegExp(String.raw
|
|
50
50
|
`^(?:(?=${
|
|
51
51
|
starting
|
|
52
|
-
})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr
|
|
52
|
+
})(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr[^\S\n]*>)${starting && '+'})?${
|
|
53
53
|
typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source
|
|
54
54
|
}`);
|
|
55
55
|
}
|
|
@@ -94,8 +94,8 @@ const isStartTight = reduce((source: string, context: MarkdownParser.Context, ex
|
|
|
94
94
|
case '<':
|
|
95
95
|
switch (true) {
|
|
96
96
|
case source.length >= 5
|
|
97
|
-
&& source
|
|
98
|
-
&& source
|
|
97
|
+
&& source.slice(0, 4) === '<wbr'
|
|
98
|
+
&& (source[5] === '>' || /^<wbr[^\S\n]*>/.test(source)):
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
return true;
|