securemark 0.268.2 → 0.269.0
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 +40 -32
- package/markdown.d.ts +59 -41
- package/package.json +1 -1
- package/src/parser/autolink.test.ts +2 -2
- package/src/parser/autolink.ts +5 -12
- package/src/parser/block/paragraph.test.ts +4 -2
- package/src/parser/block/paragraph.ts +3 -2
- package/src/parser/block/reply/quote.test.ts +2 -2
- package/src/parser/block/reply/quote.ts +8 -12
- package/src/parser/inline/autolink/url.test.ts +2 -0
- package/src/parser/inline/autolink/url.ts +13 -2
- package/src/parser/inline/autolink.ts +33 -30
- package/src/parser/inline/extension/placeholder.test.ts +1 -1
- package/src/parser/inline/link.ts +8 -3
- package/src/parser/inline/media.ts +6 -1
- package/src/parser/inline/shortmedia.ts +12 -3
- package/src/parser/inline.test.ts +6 -9
- package/src/parser/inline.ts +8 -7
- package/src/parser/source/escapable.ts +5 -1
- package/src/parser/source/text.ts +5 -1
- package/src/parser/source/unescapable.ts +7 -1
- package/src/parser/util.ts +0 -10
- package/src/parser/visibility.ts +1 -2
- package/src/util/quote.test.ts +2 -2
package/CHANGELOG.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.
|
|
1
|
+
/*! securemark v0.269.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
|
|
2
2
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
3
3
|
if(typeof exports === 'object' && typeof module === 'object')
|
|
4
4
|
module.exports = factory(require("Prism"), require("DOMPurify"));
|
|
@@ -4274,14 +4274,11 @@ exports.parse = parse;
|
|
|
4274
4274
|
Object.defineProperty(exports, "__esModule", ({
|
|
4275
4275
|
value: true
|
|
4276
4276
|
}));
|
|
4277
|
-
exports.
|
|
4277
|
+
exports.autolink = void 0;
|
|
4278
4278
|
const combinator_1 = __webpack_require__(2087);
|
|
4279
|
-
const link_1 = __webpack_require__(9628);
|
|
4280
4279
|
const autolink_1 = __webpack_require__(6051);
|
|
4281
4280
|
const source_1 = __webpack_require__(6743);
|
|
4282
|
-
|
|
4283
|
-
exports.autolink = (0, combinator_1.lazy)(() => (0, combinator_1.some)((0, combinator_1.line)((0, combinator_1.subsequence)([exports.lineurl, (0, combinator_1.some)((0, combinator_1.union)([autolink_1.autolink, source_1.linebreak, source_1.unescsource]))]))));
|
|
4284
|
-
exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.focus)(/^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, util_1.format)((0, combinator_1.tails)([(0, source_1.str)('!'), link_1.link]))));
|
|
4281
|
+
exports.autolink = (0, combinator_1.lazy)(() => (0, combinator_1.convert)(source => `\r${source}`, (0, combinator_1.some)((0, combinator_1.union)([autolink_1.autolink, source_1.linebreak, source_1.unescsource]))));
|
|
4285
4282
|
|
|
4286
4283
|
/***/ }),
|
|
4287
4284
|
|
|
@@ -5378,7 +5375,7 @@ const combinator_1 = __webpack_require__(2087);
|
|
|
5378
5375
|
const inline_1 = __webpack_require__(1160);
|
|
5379
5376
|
const visibility_1 = __webpack_require__(7618);
|
|
5380
5377
|
const dom_1 = __webpack_require__(3252);
|
|
5381
|
-
exports.paragraph = (0, combinator_1.block)((0, combinator_1.fmap)((0, visibility_1.visualize)((0, combinator_1.trimEnd)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline])))), ns => [(0, dom_1.html)('p', (0, dom_1.defrag)(ns))]));
|
|
5378
|
+
exports.paragraph = (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.convert)(source => `\r${source}`, (0, visibility_1.visualize)((0, combinator_1.trimEnd)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]))))), ns => [(0, dom_1.html)('p', (0, dom_1.defrag)(ns))]));
|
|
5382
5379
|
|
|
5383
5380
|
/***/ }),
|
|
5384
5381
|
|
|
@@ -5462,7 +5459,6 @@ const combinator_1 = __webpack_require__(2087);
|
|
|
5462
5459
|
const math_1 = __webpack_require__(8946);
|
|
5463
5460
|
const autolink_1 = __webpack_require__(6051);
|
|
5464
5461
|
const source_1 = __webpack_require__(6743);
|
|
5465
|
-
const autolink_2 = __webpack_require__(7185);
|
|
5466
5462
|
const dom_1 = __webpack_require__(3252);
|
|
5467
5463
|
exports.syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
|
|
5468
5464
|
exports.quote = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, false, (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)('>', (0, combinator_1.union)([(0, combinator_1.rewrite)((0, combinator_1.some)((0, combinator_1.validate)(new RegExp(exports.syntax.source.split('|')[0]), source_1.anyline)), qblock), (0, combinator_1.rewrite)((0, combinator_1.validate)(new RegExp(exports.syntax.source.split('|').slice(1).join('|')), source_1.anyline), (0, combinator_1.line)((0, combinator_1.union)([(0, source_1.str)(/^.+/)])))])), ns => [(0, dom_1.html)('span', ns.length > 1 ? {
|
|
@@ -5482,7 +5478,7 @@ const qblock = ({
|
|
|
5482
5478
|
const quotes = source.match(/^>+[^\S\n]/mg);
|
|
5483
5479
|
const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
|
|
5484
5480
|
const nodes = (0, parser_1.eval)(text({
|
|
5485
|
-
source: content
|
|
5481
|
+
source: `\r${content}`,
|
|
5486
5482
|
context
|
|
5487
5483
|
}), []);
|
|
5488
5484
|
nodes.unshift(quotes.shift());
|
|
@@ -5508,7 +5504,7 @@ const qblock = ({
|
|
|
5508
5504
|
nodes.unshift('');
|
|
5509
5505
|
return [nodes, ''];
|
|
5510
5506
|
};
|
|
5511
|
-
const text = (0, combinator_1.some)((0, combinator_1.
|
|
5507
|
+
const text = (0, combinator_1.some)((0, combinator_1.union)([math_1.math, autolink_1.autolink, source_1.linebreak, source_1.unescsource]));
|
|
5512
5508
|
|
|
5513
5509
|
/***/ }),
|
|
5514
5510
|
|
|
@@ -5702,7 +5698,7 @@ const shortmedia_1 = __webpack_require__(4189);
|
|
|
5702
5698
|
const autolink_1 = __webpack_require__(6051);
|
|
5703
5699
|
const bracket_1 = __webpack_require__(5196);
|
|
5704
5700
|
const source_1 = __webpack_require__(6743);
|
|
5705
|
-
exports.inline = (0, combinator_1.union)([annotation_1.annotation, reference_1.reference, template_1.template, comment_1.comment, math_1.math, extension_1.extension, ruby_1.ruby, link_1.
|
|
5701
|
+
exports.inline = (0, combinator_1.union)([annotation_1.annotation, reference_1.reference, template_1.template, comment_1.comment, math_1.math, extension_1.extension, ruby_1.ruby, link_1.textlink, link_1.linemedialink, media_1.linemedia, html_1.html, insertion_1.insertion, deletion_1.deletion, mark_1.mark, strong_1.strong, emphasis_1.emphasis, code_1.code, htmlentity_1.htmlentity, shortmedia_1.lineshortmedia, autolink_1.autolink, bracket_1.bracket, source_1.text]);
|
|
5706
5702
|
var indexee_1 = __webpack_require__(1269);
|
|
5707
5703
|
Object.defineProperty(exports, "indexee", ({
|
|
5708
5704
|
enumerable: true,
|
|
@@ -5776,7 +5772,7 @@ const hashnum_1 = __webpack_require__(5631);
|
|
|
5776
5772
|
const anchor_1 = __webpack_require__(6495);
|
|
5777
5773
|
const source_1 = __webpack_require__(6743);
|
|
5778
5774
|
const util_1 = __webpack_require__(9437);
|
|
5779
|
-
exports.autolink = (0, combinator_1.
|
|
5775
|
+
exports.autolink = (0, combinator_1.validate)(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i, (0, combinator_1.constraint)(2 /* State.autolink */, false, (0, combinator_1.syntax)(2 /* Syntax.autolink */, 1, 1, ~1 /* State.shortcut */, (0, combinator_1.union)([(0, combinator_1.some)((0, combinator_1.union)([url_1.lineurl])), (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.union)([url_1.url, email_1.email,
|
|
5780
5776
|
// Escape unmatched email-like strings.
|
|
5781
5777
|
(0, combinator_1.focus)(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i, ({
|
|
5782
5778
|
source
|
|
@@ -5793,7 +5789,7 @@ exports.autolink = (0, combinator_1.fmap)((0, combinator_1.validate)(/^(?:[@#>0-
|
|
|
5793
5789
|
// Escape unmatched hashtag-like strings.
|
|
5794
5790
|
(0, source_1.str)(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', hashtag_1.emoji), 'u')),
|
|
5795
5791
|
// Escape invalid leading characters.
|
|
5796
|
-
(0, source_1.str)(/^[0-9\p{Sc}](?=>)/u), anchor_1.anchor]))
|
|
5792
|
+
(0, source_1.str)(/^[0-9\p{Sc}](?=>)/u), anchor_1.anchor])), ns => ns.length === 1 ? ns : [(0, util_1.stringify)(ns)])]))));
|
|
5797
5793
|
|
|
5798
5794
|
/***/ }),
|
|
5799
5795
|
|
|
@@ -5949,12 +5945,13 @@ exports.hashtag = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combin
|
|
|
5949
5945
|
Object.defineProperty(exports, "__esModule", ({
|
|
5950
5946
|
value: true
|
|
5951
5947
|
}));
|
|
5952
|
-
exports.url = void 0;
|
|
5948
|
+
exports.lineurl = exports.url = void 0;
|
|
5953
5949
|
const combinator_1 = __webpack_require__(2087);
|
|
5954
5950
|
const link_1 = __webpack_require__(9628);
|
|
5955
5951
|
const source_1 = __webpack_require__(6743);
|
|
5956
5952
|
const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
|
|
5957
5953
|
exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['http://', 'https://'], (0, combinator_1.rewrite)((0, combinator_1.open)(/^https?:\/\/(?=[\x21-\x7E])/, (0, combinator_1.focus)(/^[\x21-\x7E]+/, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.unescsource, closer)])))), (0, combinator_1.convert)(url => `{ ${url} }`, (0, combinator_1.union)([link_1.unsafelink])))));
|
|
5954
|
+
exports.lineurl = (0, combinator_1.open)(source_1.linebreak, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.focus)(/^https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink))]));
|
|
5958
5955
|
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combinator_1.precedence)(2, (0, combinator_1.union)([(0, combinator_1.surround)('(', (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')'), ')', true), (0, combinator_1.surround)('[', (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']'), ']', true), (0, combinator_1.surround)('{', (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}'), '}', true), (0, combinator_1.surround)('"', (0, combinator_1.precedence)(8, (0, combinator_1.some)(source_1.unescsource, '"')), '"', true)]))));
|
|
5959
5956
|
|
|
5960
5957
|
/***/ }),
|
|
@@ -6419,7 +6416,7 @@ exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0,
|
|
|
6419
6416
|
Object.defineProperty(exports, "__esModule", ({
|
|
6420
6417
|
value: true
|
|
6421
6418
|
}));
|
|
6422
|
-
exports.resolve = exports.option = exports.uri = exports.unsafelink = exports.link = void 0;
|
|
6419
|
+
exports.resolve = exports.option = exports.uri = exports.unsafelink = exports.linemedialink = exports.medialink = exports.textlink = exports.link = void 0;
|
|
6423
6420
|
const combinator_1 = __webpack_require__(2087);
|
|
6424
6421
|
const inline_1 = __webpack_require__(1160);
|
|
6425
6422
|
const html_1 = __webpack_require__(5994);
|
|
@@ -6432,11 +6429,12 @@ const optspec = {
|
|
|
6432
6429
|
rel: ['nofollow']
|
|
6433
6430
|
};
|
|
6434
6431
|
Object.setPrototypeOf(optspec, null);
|
|
6435
|
-
exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'], (0, combinator_1.union)([medialink, textlink])));
|
|
6436
|
-
|
|
6432
|
+
exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'], (0, combinator_1.union)([exports.medialink, exports.textlink])));
|
|
6433
|
+
exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(16 /* State.link */, false, (0, combinator_1.syntax)(16 /* Syntax.link */, 2, 10, 502 /* State.linkers */ | 8 /* State.media */, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[/^\\?\n/, 9], [']', 2]]), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))])), ([params, content = []], rest, context) => {
|
|
6437
6434
|
return parse(content, params, rest, context);
|
|
6438
6435
|
}))));
|
|
6439
|
-
|
|
6436
|
+
exports.medialink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(16 /* State.link */ | 8 /* State.media */, false, (0, combinator_1.syntax)(16 /* Syntax.link */, 2, 10, 502 /* State.linkers */, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.sequence)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.union)([inline_1.media, inline_1.shortmedia]), ']')), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))])), ([params, content = []], rest, context) => parse(content, params, rest, context)))));
|
|
6437
|
+
exports.linemedialink = (0, combinator_1.surround)(source_1.linebreak, (0, combinator_1.union)([exports.medialink]), /^(?=[^\S\n]*(?:$|\n))/);
|
|
6440
6438
|
exports.unsafelink = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(10, (0, combinator_1.precedence)(2, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.some)((0, combinator_1.union)([source_1.unescsource]), ']'), ']')), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))])), ([params, content = []], rest, context) => parse(content, params, rest, context)))));
|
|
6441
6439
|
exports.uri = (0, combinator_1.union)([(0, combinator_1.open)(/^[^\S\n]+/, (0, source_1.str)(/^\S+/)), (0, source_1.str)(/^[^\s{}]+/)]);
|
|
6442
6440
|
exports.option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+nofollow(?=[^\S\n]|})/), () => [` rel="nofollow"`]), (0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|})/), (0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[^\s{}]+/), opt => [` \\${opt.slice(1)}`])]);
|
|
@@ -6601,7 +6599,7 @@ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, comb
|
|
|
6601
6599
|
Object.defineProperty(exports, "__esModule", ({
|
|
6602
6600
|
value: true
|
|
6603
6601
|
}));
|
|
6604
|
-
exports.media = void 0;
|
|
6602
|
+
exports.linemedia = exports.media = void 0;
|
|
6605
6603
|
const combinator_1 = __webpack_require__(2087);
|
|
6606
6604
|
const link_1 = __webpack_require__(9628);
|
|
6607
6605
|
const html_1 = __webpack_require__(5994);
|
|
@@ -6646,6 +6644,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '
|
|
|
6646
6644
|
context
|
|
6647
6645
|
});
|
|
6648
6646
|
}))))));
|
|
6647
|
+
exports.linemedia = (0, combinator_1.surround)(source_1.linebreak, (0, combinator_1.union)([exports.media]), /^(?=[^\S\n]*(?:$|\n))/);
|
|
6649
6648
|
const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)((0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, 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)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, 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)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, 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)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true)])));
|
|
6650
6649
|
const option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*x[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` width="${opt.slice(1).split('x')[0]}"`, ` height="${opt.slice(1).split('x')[1]}"`]), (0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*:[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` aspect-ratio="${opt.slice(1).split(':').join('/')}"`]), link_1.option]);
|
|
6651
6650
|
function sanitize(target, uri, alt) {
|
|
@@ -6825,11 +6824,13 @@ function attributes(texts, rubies) {
|
|
|
6825
6824
|
Object.defineProperty(exports, "__esModule", ({
|
|
6826
6825
|
value: true
|
|
6827
6826
|
}));
|
|
6828
|
-
exports.shortmedia = void 0;
|
|
6827
|
+
exports.lineshortmedia = exports.shortmedia = void 0;
|
|
6829
6828
|
const combinator_1 = __webpack_require__(2087);
|
|
6830
6829
|
const url_1 = __webpack_require__(4318);
|
|
6831
6830
|
const media_1 = __webpack_require__(1303);
|
|
6831
|
+
const source_1 = __webpack_require__(6743);
|
|
6832
6832
|
exports.shortmedia = (0, combinator_1.rewrite)((0, combinator_1.constraint)(8 /* State.media */, false, (0, combinator_1.open)('!', url_1.url)), (0, combinator_1.convert)(source => `!{ ${source.slice(1)} }`, (0, combinator_1.union)([media_1.media])));
|
|
6833
|
+
exports.lineshortmedia = (0, combinator_1.open)(source_1.linebreak, (0, combinator_1.focus)(/^!https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, combinator_1.convert)(source => `!{ ${source.slice(1)} }`, (0, combinator_1.union)([media_1.media]))));
|
|
6833
6834
|
|
|
6834
6835
|
/***/ }),
|
|
6835
6836
|
|
|
@@ -7336,7 +7337,8 @@ const combinator_1 = __webpack_require__(2087);
|
|
|
7336
7337
|
const text_1 = __webpack_require__(7763);
|
|
7337
7338
|
const delimiter = /[\s\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/;
|
|
7338
7339
|
exports.escsource = (0, combinator_1.creation)(1, false, ({
|
|
7339
|
-
source
|
|
7340
|
+
source,
|
|
7341
|
+
context
|
|
7340
7342
|
}) => {
|
|
7341
7343
|
if (source === '') return;
|
|
7342
7344
|
const i = source.search(delimiter);
|
|
@@ -7345,6 +7347,9 @@ exports.escsource = (0, combinator_1.creation)(1, false, ({
|
|
|
7345
7347
|
return [[source], ''];
|
|
7346
7348
|
case 0:
|
|
7347
7349
|
switch (source[0]) {
|
|
7350
|
+
case '\r':
|
|
7351
|
+
context.resources && ++context.resources.clock;
|
|
7352
|
+
return [[], source.slice(1)];
|
|
7348
7353
|
case '\x1B':
|
|
7349
7354
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
7350
7355
|
case '\\':
|
|
@@ -7458,6 +7463,9 @@ exports.text = (0, combinator_1.creation)(1, false, ({
|
|
|
7458
7463
|
return [[source], ''];
|
|
7459
7464
|
case 0:
|
|
7460
7465
|
switch (source[0]) {
|
|
7466
|
+
case '\r':
|
|
7467
|
+
context.resources && ++context.resources.clock;
|
|
7468
|
+
return [[], source.slice(1)];
|
|
7461
7469
|
case '\x1B':
|
|
7462
7470
|
case '\\':
|
|
7463
7471
|
switch (source[1]) {
|
|
@@ -7489,7 +7497,7 @@ exports.text = (0, combinator_1.creation)(1, false, ({
|
|
|
7489
7497
|
}
|
|
7490
7498
|
});
|
|
7491
7499
|
exports.txt = (0, combinator_1.union)([exports.text]);
|
|
7492
|
-
exports.linebreak = (0, combinator_1.focus)(
|
|
7500
|
+
exports.linebreak = (0, combinator_1.focus)(/^[\r\n]/, (0, combinator_1.union)([exports.text]));
|
|
7493
7501
|
function isAlphanumeric(char) {
|
|
7494
7502
|
if (char < '0' || '\x7F' < char) return false;
|
|
7495
7503
|
return '0' <= char && char <= '9' || 'a' <= char && char <= 'z' || 'A' <= char && char <= 'Z';
|
|
@@ -7511,7 +7519,8 @@ exports.unescsource = void 0;
|
|
|
7511
7519
|
const combinator_1 = __webpack_require__(2087);
|
|
7512
7520
|
const text_1 = __webpack_require__(7763);
|
|
7513
7521
|
exports.unescsource = (0, combinator_1.creation)(1, false, ({
|
|
7514
|
-
source
|
|
7522
|
+
source,
|
|
7523
|
+
context
|
|
7515
7524
|
}) => {
|
|
7516
7525
|
if (source === '') return;
|
|
7517
7526
|
const i = source.search(text_1.delimiter);
|
|
@@ -7520,6 +7529,11 @@ exports.unescsource = (0, combinator_1.creation)(1, false, ({
|
|
|
7520
7529
|
return [[source], ''];
|
|
7521
7530
|
case 0:
|
|
7522
7531
|
{
|
|
7532
|
+
switch (source[0]) {
|
|
7533
|
+
case '\r':
|
|
7534
|
+
context.resources && ++context.resources.clock;
|
|
7535
|
+
return [[], source.slice(1)];
|
|
7536
|
+
}
|
|
7523
7537
|
const b = source[0] !== '\n' && source[0].trimStart() === '';
|
|
7524
7538
|
const i = b || (0, text_1.isAlphanumeric)(source[0]) ? source.search(b ? text_1.nonWhitespace : text_1.nonAlphanumeric) || 1 : 1;
|
|
7525
7539
|
return [[source.slice(0, i - +b || 1)], source.slice(i - +b || 1)];
|
|
@@ -7532,7 +7546,7 @@ exports.unescsource = (0, combinator_1.creation)(1, false, ({
|
|
|
7532
7546
|
/***/ }),
|
|
7533
7547
|
|
|
7534
7548
|
/***/ 9437:
|
|
7535
|
-
/***/ ((__unused_webpack_module, exports
|
|
7549
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
7536
7550
|
|
|
7537
7551
|
"use strict";
|
|
7538
7552
|
|
|
@@ -7540,12 +7554,7 @@ exports.unescsource = (0, combinator_1.creation)(1, false, ({
|
|
|
7540
7554
|
Object.defineProperty(exports, "__esModule", ({
|
|
7541
7555
|
value: true
|
|
7542
7556
|
}));
|
|
7543
|
-
exports.stringify =
|
|
7544
|
-
const combinator_1 = __webpack_require__(2087);
|
|
7545
|
-
function format(parser) {
|
|
7546
|
-
return (0, combinator_1.convert)(source => source.replace(/(?<=^!?)https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=[^\S\n]*(?:$|\n))/gm, '{ $& }'), parser);
|
|
7547
|
-
}
|
|
7548
|
-
exports.format = format;
|
|
7557
|
+
exports.stringify = void 0;
|
|
7549
7558
|
function stringify(nodes) {
|
|
7550
7559
|
let acc = '';
|
|
7551
7560
|
for (let i = 0; i < nodes.length; ++i) {
|
|
@@ -7577,13 +7586,12 @@ const parser_1 = __webpack_require__(6728);
|
|
|
7577
7586
|
const combinator_1 = __webpack_require__(2087);
|
|
7578
7587
|
const htmlentity_1 = __webpack_require__(1562);
|
|
7579
7588
|
const source_1 = __webpack_require__(6743);
|
|
7580
|
-
const util_1 = __webpack_require__(9437);
|
|
7581
7589
|
const normalize_1 = __webpack_require__(185);
|
|
7582
7590
|
const memoize_1 = __webpack_require__(1808);
|
|
7583
7591
|
const array_1 = __webpack_require__(8112);
|
|
7584
7592
|
function visualize(parser) {
|
|
7585
7593
|
const blankline = new RegExp(/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+$/.source.replace('IHN', `(?:${normalize_1.invisibleHTMLEntityNames.join('|')})`), 'gm');
|
|
7586
|
-
return (0, combinator_1.union)([(0, combinator_1.convert)(source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')), (0, combinator_1.verify)(
|
|
7594
|
+
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]))]);
|
|
7587
7595
|
}
|
|
7588
7596
|
exports.visualize = visualize;
|
|
7589
7597
|
function hasVisible(nodes, {
|
package/markdown.d.ts
CHANGED
|
@@ -346,7 +346,7 @@ export namespace MarkdownParser {
|
|
|
346
346
|
BlockquoteParser,
|
|
347
347
|
PlaceholderParser,
|
|
348
348
|
InlineParser.MediaParser,
|
|
349
|
-
InlineParser.
|
|
349
|
+
InlineParser.ShortMediaParser,
|
|
350
350
|
]>,
|
|
351
351
|
SourceParser.EmptyLineParser,
|
|
352
352
|
InlineParser,
|
|
@@ -598,13 +598,10 @@ export namespace MarkdownParser {
|
|
|
598
598
|
export interface TextParser extends
|
|
599
599
|
Block<'reply/quote/text'>,
|
|
600
600
|
Parser<string | HTMLElement, Context, [
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
SourceParser.LinebreakParser,
|
|
606
|
-
SourceParser.UnescapableSourceParser,
|
|
607
|
-
]>,
|
|
601
|
+
InlineParser.MathParser,
|
|
602
|
+
InlineParser.AutolinkParser,
|
|
603
|
+
SourceParser.LinebreakParser,
|
|
604
|
+
SourceParser.UnescapableSourceParser,
|
|
608
605
|
]> {
|
|
609
606
|
}
|
|
610
607
|
export interface PlaceholderParser extends
|
|
@@ -633,8 +630,9 @@ export namespace MarkdownParser {
|
|
|
633
630
|
InlineParser.MathParser,
|
|
634
631
|
InlineParser.ExtensionParser,
|
|
635
632
|
InlineParser.RubyParser,
|
|
636
|
-
InlineParser.LinkParser,
|
|
637
|
-
InlineParser.
|
|
633
|
+
InlineParser.LinkParser.TextLinkParser,
|
|
634
|
+
InlineParser.LinkParser.LineMediaLinkParser,
|
|
635
|
+
InlineParser.MediaParser.LineMediaParser,
|
|
638
636
|
InlineParser.HTMLParser,
|
|
639
637
|
InlineParser.InsertionParser,
|
|
640
638
|
InlineParser.DeletionParser,
|
|
@@ -643,7 +641,7 @@ export namespace MarkdownParser {
|
|
|
643
641
|
InlineParser.EmphasisParser,
|
|
644
642
|
InlineParser.CodeParser,
|
|
645
643
|
InlineParser.HTMLEntityParser,
|
|
646
|
-
InlineParser.
|
|
644
|
+
InlineParser.ShortMediaParser.LineShortMediaParser,
|
|
647
645
|
InlineParser.AutolinkParser,
|
|
648
646
|
InlineParser.BracketParser,
|
|
649
647
|
SourceParser.TextParser,
|
|
@@ -842,6 +840,12 @@ export namespace MarkdownParser {
|
|
|
842
840
|
]> {
|
|
843
841
|
}
|
|
844
842
|
export namespace LinkParser {
|
|
843
|
+
export interface LineMediaLinkParser extends
|
|
844
|
+
Inline<'link/linemedialink'>,
|
|
845
|
+
Parser<HTMLElement, Context, [
|
|
846
|
+
LinkParser.MediaLinkParser,
|
|
847
|
+
]> {
|
|
848
|
+
}
|
|
845
849
|
export interface TextLinkParser extends
|
|
846
850
|
Inline<'link/textlink'>,
|
|
847
851
|
Parser<HTMLAnchorElement, Context, [
|
|
@@ -856,7 +860,7 @@ export namespace MarkdownParser {
|
|
|
856
860
|
Parser<HTMLAnchorElement, Context, [
|
|
857
861
|
Parser<HTMLElement[], Context, [
|
|
858
862
|
MediaParser,
|
|
859
|
-
|
|
863
|
+
ShortMediaParser,
|
|
860
864
|
]>,
|
|
861
865
|
LinkParser.ParameterParser,
|
|
862
866
|
]> {
|
|
@@ -872,7 +876,7 @@ export namespace MarkdownParser {
|
|
|
872
876
|
Inline<'link/content'>,
|
|
873
877
|
Parser<(HTMLElement | string)[], Context, [
|
|
874
878
|
MediaParser,
|
|
875
|
-
|
|
879
|
+
ShortMediaParser,
|
|
876
880
|
InlineParser,
|
|
877
881
|
]> {
|
|
878
882
|
}
|
|
@@ -917,6 +921,12 @@ export namespace MarkdownParser {
|
|
|
917
921
|
]> {
|
|
918
922
|
}
|
|
919
923
|
export namespace MediaParser {
|
|
924
|
+
export interface LineMediaParser extends
|
|
925
|
+
Inline<'media/linemedia'>,
|
|
926
|
+
Parser<HTMLElement, Context, [
|
|
927
|
+
MediaParser,
|
|
928
|
+
]> {
|
|
929
|
+
}
|
|
920
930
|
export interface TextParser extends
|
|
921
931
|
Inline<'media/text'>,
|
|
922
932
|
Parser<string[], Context, [
|
|
@@ -1060,28 +1070,41 @@ export namespace MarkdownParser {
|
|
|
1060
1070
|
Inline<'unsafehtmlentity'>,
|
|
1061
1071
|
Parser<string, Context, []> {
|
|
1062
1072
|
}
|
|
1063
|
-
export interface
|
|
1073
|
+
export interface ShortMediaParser extends
|
|
1064
1074
|
// !https://host
|
|
1065
1075
|
Inline<'shortmedia'>,
|
|
1066
1076
|
Parser<HTMLElement, Context, [
|
|
1067
1077
|
MediaParser,
|
|
1068
1078
|
]> {
|
|
1069
1079
|
}
|
|
1080
|
+
export namespace ShortMediaParser {
|
|
1081
|
+
export interface LineShortMediaParser extends
|
|
1082
|
+
Inline<'shortmedia/lineshortmedia'>,
|
|
1083
|
+
Parser<HTMLElement, Context, [
|
|
1084
|
+
MediaParser,
|
|
1085
|
+
]> {
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1070
1088
|
export interface AutolinkParser extends
|
|
1071
1089
|
Inline<'autolink'>,
|
|
1072
1090
|
Parser<HTMLElement | string, Context, [
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1091
|
+
Parser<HTMLElement | string, Context, [
|
|
1092
|
+
AutolinkParser.UrlParser.LineUrlParser,
|
|
1093
|
+
]>,
|
|
1094
|
+
Parser<HTMLElement | string, Context, [
|
|
1095
|
+
AutolinkParser.UrlParser,
|
|
1096
|
+
AutolinkParser.EmailParser,
|
|
1097
|
+
SourceParser.StrParser,
|
|
1098
|
+
AutolinkParser.ChannelParser,
|
|
1099
|
+
AutolinkParser.AccountParser,
|
|
1100
|
+
SourceParser.StrParser,
|
|
1101
|
+
SourceParser.StrParser,
|
|
1102
|
+
AutolinkParser.HashtagParser,
|
|
1103
|
+
AutolinkParser.HashnumParser,
|
|
1104
|
+
SourceParser.StrParser,
|
|
1105
|
+
SourceParser.StrParser,
|
|
1106
|
+
AutolinkParser.AnchorParser,
|
|
1107
|
+
]>,
|
|
1085
1108
|
]> {
|
|
1086
1109
|
}
|
|
1087
1110
|
export namespace AutolinkParser {
|
|
@@ -1093,6 +1116,13 @@ export namespace MarkdownParser {
|
|
|
1093
1116
|
]> {
|
|
1094
1117
|
}
|
|
1095
1118
|
export namespace UrlParser {
|
|
1119
|
+
export interface LineUrlParser extends
|
|
1120
|
+
Inline<'url/lineurl'>,
|
|
1121
|
+
Parser<string | HTMLElement, Context, [
|
|
1122
|
+
SourceParser.StrParser,
|
|
1123
|
+
InlineParser.LinkParser.UnsafeLinkParser,
|
|
1124
|
+
]> {
|
|
1125
|
+
}
|
|
1096
1126
|
export interface BracketParser extends
|
|
1097
1127
|
Inline<'url/bracket'>,
|
|
1098
1128
|
Parser<string, Context, [
|
|
@@ -1176,23 +1206,11 @@ export namespace MarkdownParser {
|
|
|
1176
1206
|
export interface AutolinkParser extends
|
|
1177
1207
|
Markdown<'autolink'>,
|
|
1178
1208
|
Parser<string | HTMLElement, Context, [
|
|
1179
|
-
AutolinkParser
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
SourceParser.LinebreakParser,
|
|
1183
|
-
SourceParser.UnescapableSourceParser,
|
|
1184
|
-
]>,
|
|
1209
|
+
InlineParser.AutolinkParser,
|
|
1210
|
+
SourceParser.LinebreakParser,
|
|
1211
|
+
SourceParser.UnescapableSourceParser,
|
|
1185
1212
|
]> {
|
|
1186
1213
|
}
|
|
1187
|
-
export namespace AutolinkParser {
|
|
1188
|
-
export interface LineUrlParser extends
|
|
1189
|
-
Markdown<'autolink/lineurl'>,
|
|
1190
|
-
Parser<string | HTMLElement, Context, [
|
|
1191
|
-
SourceParser.StrParser,
|
|
1192
|
-
InlineParser.LinkParser,
|
|
1193
|
-
]> {
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
1214
|
export namespace SourceParser {
|
|
1197
1215
|
interface Source<T extends string> extends Markdown<`source/${T}`> { }
|
|
1198
1216
|
export interface TextParser extends
|
package/package.json
CHANGED
|
@@ -6,8 +6,8 @@ describe('Unit: parser/autolink', () => {
|
|
|
6
6
|
const parser = (source: string) => autolink({ source, context: {} });
|
|
7
7
|
|
|
8
8
|
it('basic', () => {
|
|
9
|
-
assert.deepStrictEqual(inspect(parser('
|
|
10
|
-
assert.deepStrictEqual(inspect(parser('!http://host')), [['!', '<a class="url" href="http://host" target="_blank">http://host
|
|
9
|
+
assert.deepStrictEqual(inspect(parser('http://host#\\')), [['<a class="url" href="http://host#\\" target="_blank">http://host#\\</a>'], '']);
|
|
10
|
+
assert.deepStrictEqual(inspect(parser('!http://host#\\')), [['!', '<a class="url" href="http://host#\\" target="_blank">http://host#\\</a>'], '']);
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('#a')), [['<a class="hashtag" href="/hashtags/a">#a</a>'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('@a#b')), [['<a class="channel" href="/@a?ch=b">@a#b</a>'], '']);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '<br>'], '']);
|
package/src/parser/autolink.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../markdown';
|
|
2
|
-
import { union,
|
|
3
|
-
import { link } from './inline/link';
|
|
2
|
+
import { union, some, convert, lazy } from '../combinator';
|
|
4
3
|
import { autolink as autolink_ } from './inline/autolink';
|
|
5
|
-
import { linebreak, unescsource
|
|
6
|
-
import { format } from './util';
|
|
4
|
+
import { linebreak, unescsource } from './source';
|
|
7
5
|
|
|
8
6
|
export import AutolinkParser = MarkdownParser.AutolinkParser;
|
|
9
7
|
|
|
10
|
-
export const autolink: AutolinkParser = lazy(() =>
|
|
11
|
-
|
|
8
|
+
export const autolink: AutolinkParser = lazy(() =>
|
|
9
|
+
convert(source => `\r${source}`,
|
|
12
10
|
some(union([
|
|
13
11
|
autolink_,
|
|
14
12
|
linebreak,
|
|
15
13
|
unescsource,
|
|
16
|
-
]))
|
|
17
|
-
]))));
|
|
18
|
-
|
|
19
|
-
export const lineurl: AutolinkParser.LineUrlParser = lazy(() => focus(
|
|
20
|
-
/^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
21
|
-
format(tails([str('!'), link]))));
|
|
14
|
+
]))));
|
|
@@ -30,9 +30,11 @@ describe('Unit: parser/block/paragraph', () => {
|
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('_a\n<wbr>_\nb')), [['<p>_a<br><wbr>_<br>b</p>'], '']);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('*a\n<wbr>*\nb')), [['<p>*a<br><wbr>*<br>b</p>'], '']);
|
|
32
32
|
assert.deepStrictEqual(inspect(parser('==a\n<wbr>==\nb')), [['<p>==a<br><wbr>==<br>b</p>'], '']);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('http://host
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('http://host#\\')), [['<p><a class="url" href="http://host#\\" target="_blank">http://host#\\</a></p>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser('a\nhttp://host#\\ \nb')), [['<p>a<br><a class="url" href="http://host#\\" target="_blank">http://host#\\</a><br>b</p>'], '']);
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('!http://host
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('!http://host#\\')), [['<p><a href="http://host#\\" target="_blank"><img class="media" data-src="http://host#\\" alt=""></a></p>'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('!http://host#\\ a')), [['<p>!<a class="url" href="http://host#" target="_blank">http://host#</a> a</p>'], '']);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser(' !http://host#\\')), [['<p> !<a class="url" href="http://host#" target="_blank">http://host#</a></p>'], '']);
|
|
36
38
|
assert.deepStrictEqual(inspect(parser('\ta')), [['<p>\ta</p>'], '']);
|
|
37
39
|
});
|
|
38
40
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ParagraphParser } from '../block';
|
|
2
|
-
import { union, some, block, trimEnd, fmap } from '../../combinator';
|
|
2
|
+
import { union, some, block, convert, trimEnd, fmap } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { visualize } from '../visibility';
|
|
5
5
|
import { html, defrag } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
export const paragraph: ParagraphParser = block(fmap(
|
|
8
|
-
|
|
8
|
+
convert(source => `\r${source}`,
|
|
9
|
+
visualize(trimEnd(some(union([inline]))))),
|
|
9
10
|
ns => [html('p', defrag(ns))]));
|
|
@@ -55,9 +55,9 @@ describe('Unit: parser/block/reply/quote', () => {
|
|
|
55
55
|
assert.deepStrictEqual(inspect(parser('> $-a, $-b')), [['<span class="quote">> $-a, $-b</span>', '<br>'], '']);
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('> $a=b$')), [['<span class="quote">> <span class="math" translate="no" data-src="$a=b$">$a=b$</span></span>', '<br>'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('> ${a}$')), [['<span class="quote">> <span class="math" translate="no" data-src="${a}$">${a}$</span></span>', '<br>'], '']);
|
|
58
|
-
assert.deepStrictEqual(inspect(parser('> http://host
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('> http://host#\\')), [['<span class="quote">> <a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
|
|
59
59
|
assert.deepStrictEqual(inspect(parser('> a\n> http://host#\\ \n> b')), [['<span class="quote">> a<br>> <a class="url" href="http://host#\\" target="_blank">http://host#\\</a> <br>> b</span>', '<br>'], '']);
|
|
60
|
-
assert.deepStrictEqual(inspect(parser('> !http://host
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('> !http://host#\\')), [['<span class="quote">> !<a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ReplyParser } from '../../block';
|
|
2
2
|
import { eval } from '../../../combinator/data/parser';
|
|
3
|
-
import { union,
|
|
3
|
+
import { union, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
|
|
4
4
|
import { math } from '../../inline/math';
|
|
5
5
|
import { autolink } from '../../inline/autolink';
|
|
6
6
|
import { linebreak, unescsource, str, anyline } from '../../source';
|
|
7
|
-
import { lineurl } from '../../autolink';
|
|
8
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
8
|
|
|
10
9
|
export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
|
|
@@ -42,7 +41,7 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
|
|
|
42
41
|
assert(quotes);
|
|
43
42
|
assert(quotes.length > 0);
|
|
44
43
|
const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
|
|
45
|
-
const nodes = eval(text({ source: content
|
|
44
|
+
const nodes = eval(text({ source: `\r${content}`, context }), []);
|
|
46
45
|
nodes.unshift(quotes.shift()!);
|
|
47
46
|
for (let i = 0; i < nodes.length; ++i) {
|
|
48
47
|
const child = nodes[i] as string | Text | Element;
|
|
@@ -72,12 +71,9 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
|
|
|
72
71
|
return [nodes, ''];
|
|
73
72
|
};
|
|
74
73
|
|
|
75
|
-
const text: ReplyParser.QuoteParser.TextParser = some(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
unescsource,
|
|
82
|
-
])),
|
|
83
|
-
])));
|
|
74
|
+
const text: ReplyParser.QuoteParser.TextParser = some(union([
|
|
75
|
+
math, // quote補助関数が残した数式をパースする。他の構文で数式を残す場合はソーステキストを直接使用する。
|
|
76
|
+
autolink,
|
|
77
|
+
linebreak,
|
|
78
|
+
unescsource,
|
|
79
|
+
]));
|
|
@@ -28,6 +28,8 @@ describe('Unit: parser/inline/autolink/url', () => {
|
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('http://a#( )')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '( )']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('http://a#(\n)')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '(\n)']);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('http://[::]')), [['<a class="url" href="http://[::]" target="_blank">http://[::]</a>'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser('\rhttp://a#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>'], '']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('\rhttp://a#\\\nhttp://b#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>', '<br>', '<a class="url" href="http://b#\\" target="_blank">http://b#\\</a>'], '']);
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
it('trailing symbols', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import { union, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
|
|
2
|
+
import { union, tails, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
|
|
3
3
|
import { unsafelink } from '../link';
|
|
4
|
-
import { unescsource } from '../../source';
|
|
4
|
+
import { linebreak, unescsource, str } from '../../source';
|
|
5
5
|
|
|
6
6
|
const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
|
|
7
7
|
|
|
@@ -13,6 +13,17 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
|
|
|
13
13
|
url => `{ ${url} }`,
|
|
14
14
|
union([unsafelink])))));
|
|
15
15
|
|
|
16
|
+
export const lineurl: AutolinkParser.UrlParser.LineUrlParser = open(
|
|
17
|
+
linebreak,
|
|
18
|
+
tails([
|
|
19
|
+
str('!'),
|
|
20
|
+
focus(
|
|
21
|
+
/^https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
22
|
+
convert(
|
|
23
|
+
url => `{ ${url} }`,
|
|
24
|
+
unsafelink)),
|
|
25
|
+
]));
|
|
26
|
+
|
|
16
27
|
const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(precedence(2, union([
|
|
17
28
|
surround('(', some(union([bracket, unescsource]), ')'), ')', true),
|
|
18
29
|
surround('[', some(union([bracket, unescsource]), ']'), ']', true),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutolinkParser } from '../inline';
|
|
2
2
|
import { union, some, syntax, constraint, validate, focus, fmap } from '../../combinator';
|
|
3
|
-
import { url } from './autolink/url';
|
|
3
|
+
import { url, lineurl } from './autolink/url';
|
|
4
4
|
import { email } from './autolink/email';
|
|
5
5
|
import { channel } from './autolink/channel';
|
|
6
6
|
import { account } from './autolink/account';
|
|
@@ -11,34 +11,37 @@ import { str } from '../source';
|
|
|
11
11
|
import { Syntax, State } from '../context';
|
|
12
12
|
import { stringify } from '../util';
|
|
13
13
|
|
|
14
|
-
export const autolink: AutolinkParser =
|
|
15
|
-
validate(/^(?:[@#>0-9a-z]|\S[#>])/i,
|
|
14
|
+
export const autolink: AutolinkParser =
|
|
15
|
+
validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i,
|
|
16
16
|
constraint(State.autolink, false,
|
|
17
17
|
syntax(Syntax.autolink, 1, 1, ~State.shortcut,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
18
|
+
union([
|
|
19
|
+
some(union([lineurl])),
|
|
20
|
+
fmap(some(union([
|
|
21
|
+
url,
|
|
22
|
+
email,
|
|
23
|
+
// Escape unmatched email-like strings.
|
|
24
|
+
focus(
|
|
25
|
+
/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i,
|
|
26
|
+
({ source }) => {
|
|
27
|
+
if (source.length > 255 || source.includes('@')) return [[source], ''];
|
|
28
|
+
const i = source.indexOf('_');
|
|
29
|
+
if (i === -1) return [[source], ''];
|
|
30
|
+
return [[source.slice(0, i)], source.slice(i)];
|
|
31
|
+
}),
|
|
32
|
+
channel,
|
|
33
|
+
account,
|
|
34
|
+
// Escape unmatched account-like strings.
|
|
35
|
+
str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
|
|
36
|
+
// Escape invalid leading characters.
|
|
37
|
+
str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
|
|
38
|
+
hashtag,
|
|
39
|
+
hashnum,
|
|
40
|
+
// Escape unmatched hashtag-like strings.
|
|
41
|
+
str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
|
|
42
|
+
// Escape invalid leading characters.
|
|
43
|
+
str(/^[0-9\p{Sc}](?=>)/u),
|
|
44
|
+
anchor,
|
|
45
|
+
])),
|
|
46
|
+
ns => ns.length === 1 ? ns : [stringify(ns)]),
|
|
47
|
+
]))));
|
|
@@ -48,7 +48,7 @@ describe('Unit: parser/inline/extension/placeholder', () => {
|
|
|
48
48
|
assert.deepStrictEqual(inspect(parser('[^a[% b %][% c %]]')), [['<span class="invalid">a<span class="comment"><input type="checkbox"><span>[% b %]</span></span><span class="comment"><input type="checkbox"><span>[% c %]</span></span></span>'], '']);
|
|
49
49
|
assert.deepStrictEqual(inspect(parser('[^\\]]')), [['<span class="invalid">]</span>'], '']);
|
|
50
50
|
assert.deepStrictEqual(inspect(parser('[^(])]')), [['<span class="invalid"><span class="paren">(])</span></span>'], '']);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid"
|
|
51
|
+
assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid">!<a class="url" href="http://host" target="_blank">http://host</a></span>'], '']);
|
|
52
52
|
assert.deepStrictEqual(inspect(parser('[^[% a %]]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></span>'], '']);
|
|
53
53
|
assert.deepStrictEqual(inspect(parser('[^[% a %]b]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span>b</span>'], '']);
|
|
54
54
|
});
|
|
@@ -4,7 +4,7 @@ import { Result } from '../../combinator/data/parser';
|
|
|
4
4
|
import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, 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
|
-
import { unescsource, str } from '../source';
|
|
7
|
+
import { linebreak, unescsource, str } from '../source';
|
|
8
8
|
import { Syntax, State } from '../context';
|
|
9
9
|
import { trimNode } from '../visibility';
|
|
10
10
|
import { stringify } from '../util';
|
|
@@ -21,7 +21,7 @@ export const link: LinkParser = lazy(() => validate(['[', '{'], union([
|
|
|
21
21
|
textlink,
|
|
22
22
|
])));
|
|
23
23
|
|
|
24
|
-
const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
24
|
+
export const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
25
25
|
constraint(State.link, false,
|
|
26
26
|
syntax(Syntax.link, 2, 10, State.linkers | State.media,
|
|
27
27
|
bind(reverse(tails([
|
|
@@ -37,7 +37,7 @@ const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
|
37
37
|
return parse(content, params, rest, context);
|
|
38
38
|
}))));
|
|
39
39
|
|
|
40
|
-
const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
40
|
+
export const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
41
41
|
constraint(State.link | State.media, false,
|
|
42
42
|
syntax(Syntax.link, 2, 10, State.linkers,
|
|
43
43
|
bind(reverse(sequence([
|
|
@@ -50,6 +50,11 @@ const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
|
50
50
|
([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) =>
|
|
51
51
|
parse(content, params, rest, context)))));
|
|
52
52
|
|
|
53
|
+
export const linemedialink: LinkParser.LineMediaLinkParser = surround(
|
|
54
|
+
linebreak,
|
|
55
|
+
union([medialink]),
|
|
56
|
+
/^(?=[^\S\n]*(?:$|\n))/);
|
|
57
|
+
|
|
53
58
|
export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
|
|
54
59
|
creation(10, precedence(2,
|
|
55
60
|
bind(reverse(tails([
|
|
@@ -3,7 +3,7 @@ import { union, inits, tails, some, syntax, creation, precedence, constraint, va
|
|
|
3
3
|
import { unsafelink, uri, option as linkoption, resolve } from './link';
|
|
4
4
|
import { attributes } from './html';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
|
-
import { txt, str } from '../source';
|
|
6
|
+
import { txt, linebreak, str } from '../source';
|
|
7
7
|
import { Syntax, State } from '../context';
|
|
8
8
|
import { ReadonlyURL } from 'spica/url';
|
|
9
9
|
import { unshift, push } from 'spica/array';
|
|
@@ -61,6 +61,11 @@ export const media: MediaParser = lazy(() => validate(['![', '!{'], open(
|
|
|
61
61
|
({ source: `{ ${INSECURE_URI}${params.join('')} }${rest}`, context });
|
|
62
62
|
}))))));
|
|
63
63
|
|
|
64
|
+
export const linemedia: MediaParser.LineMediaParser = surround(
|
|
65
|
+
linebreak,
|
|
66
|
+
union([media]),
|
|
67
|
+
/^(?=[^\S\n]*(?:$|\n))/);
|
|
68
|
+
|
|
64
69
|
const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(union([
|
|
65
70
|
surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
66
71
|
surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { union, constraint, rewrite, open, convert } from '../../combinator';
|
|
1
|
+
import { ShortMediaParser } from '../inline';
|
|
2
|
+
import { union, constraint, focus, rewrite, open, convert } from '../../combinator';
|
|
3
3
|
import { url } from './autolink/url';
|
|
4
4
|
import { media } from './media';
|
|
5
|
+
import { linebreak } from '../source';
|
|
5
6
|
import { State } from '../context';
|
|
6
7
|
|
|
7
|
-
export const shortmedia:
|
|
8
|
+
export const shortmedia: ShortMediaParser = rewrite(
|
|
8
9
|
constraint(State.media, false,
|
|
9
10
|
open('!', url)),
|
|
10
11
|
convert(
|
|
11
12
|
source => `!{ ${source.slice(1)} }`,
|
|
12
13
|
union([media])));
|
|
14
|
+
|
|
15
|
+
export const lineshortmedia: ShortMediaParser.LineShortMediaParser = open(
|
|
16
|
+
linebreak,
|
|
17
|
+
focus(
|
|
18
|
+
/^!https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
19
|
+
convert(
|
|
20
|
+
source => `!{ ${source.slice(1)} }`,
|
|
21
|
+
union([media]))));
|
|
@@ -56,11 +56,11 @@ describe('Unit: parser/inline', () => {
|
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('{}')), [['{', '}'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('{a}')), [['<a class="url" href="a">a</a>'], '']);
|
|
58
58
|
assert.deepStrictEqual(inspect(parser('{{a}}')), [['<span class="template">{{a}}</span>'], '']);
|
|
59
|
-
assert.deepStrictEqual(inspect(parser('!{}')), [['!', '{', '}'], '']);
|
|
60
|
-
assert.deepStrictEqual(inspect(parser('!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
|
|
61
|
-
assert.deepStrictEqual(inspect(parser('!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
|
|
62
|
-
assert.deepStrictEqual(inspect(parser('!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
|
|
63
|
-
assert.deepStrictEqual(inspect(parser('!!{a}')), [['!', '<a
|
|
59
|
+
assert.deepStrictEqual(inspect(parser('\r!{}')), [['!', '{', '}'], '']);
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('\r!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
|
|
61
|
+
assert.deepStrictEqual(inspect(parser('\r!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
|
|
62
|
+
assert.deepStrictEqual(inspect(parser('\r!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
|
|
63
|
+
assert.deepStrictEqual(inspect(parser('\r!!{a}')), [['!', '!', '<a class="url" href="a">a</a>'], '']);
|
|
64
64
|
assert.deepStrictEqual(inspect(parser('${a}')), [['$', '<a class="url" href="a">a</a>'], '']);
|
|
65
65
|
assert.deepStrictEqual(inspect(parser('${{a}}')), [['$', '<span class="template">{{a}}</span>'], '']);
|
|
66
66
|
assert.deepStrictEqual(inspect(parser('${{{a}}}')), [['$', '<span class="template">{{{a}}}</span>'], '']);
|
|
@@ -105,11 +105,8 @@ describe('Unit: parser/inline', () => {
|
|
|
105
105
|
assert.deepStrictEqual(inspect(parser('0http://host')), [['0http', ':', '/', '/', 'host'], '']);
|
|
106
106
|
assert.deepStrictEqual(inspect(parser('0aAhttp://host')), [['0aAhttp', ':', '/', '/', 'host'], '']);
|
|
107
107
|
assert.deepStrictEqual(inspect(parser('?http://host')), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
108
|
-
assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '<a href="http://host" target="_blank"
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
109
109
|
assert.deepStrictEqual(inspect(parser('0?http://host')), [['0', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
110
|
-
assert.deepStrictEqual(inspect(parser('0!!http://host')), [['0', '!', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
|
|
111
|
-
assert.deepStrictEqual(inspect(parser('0?!http://host')), [['0', '?', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
|
|
112
|
-
assert.deepStrictEqual(inspect(parser('0!?http://host')), [['0', '!', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
113
110
|
assert.deepStrictEqual(inspect(parser('_http://host')), [['_', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
114
111
|
assert.deepStrictEqual(inspect(parser('_http://host_')), [['<em><a class="url" href="http://host" target="_blank">http://host</a></em>'], '']);
|
|
115
112
|
assert.deepStrictEqual(inspect(parser('*http://host*')), [['<strong><a class="url" href="http://host" target="_blank">http://host</a></strong>'], '']);
|
package/src/parser/inline.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { comment } from './inline/comment';
|
|
|
7
7
|
import { math } from './inline/math';
|
|
8
8
|
import { extension } from './inline/extension';
|
|
9
9
|
import { ruby } from './inline/ruby';
|
|
10
|
-
import {
|
|
10
|
+
import { textlink, linemedialink } from './inline/link';
|
|
11
11
|
import { html } from './inline/html';
|
|
12
12
|
import { insertion } from './inline/insertion';
|
|
13
13
|
import { deletion } from './inline/deletion';
|
|
@@ -15,9 +15,9 @@ import { mark } from './inline/mark';
|
|
|
15
15
|
import { emphasis } from './inline/emphasis';
|
|
16
16
|
import { strong } from './inline/strong';
|
|
17
17
|
import { code } from './inline/code';
|
|
18
|
-
import {
|
|
18
|
+
import { linemedia } from './inline/media';
|
|
19
19
|
import { htmlentity } from './inline/htmlentity';
|
|
20
|
-
import {
|
|
20
|
+
import { lineshortmedia } from './inline/shortmedia';
|
|
21
21
|
import { autolink } from './inline/autolink';
|
|
22
22
|
import { bracket } from './inline/bracket';
|
|
23
23
|
import { text } from './source';
|
|
@@ -41,7 +41,7 @@ export import CodeParser = InlineParser.CodeParser;
|
|
|
41
41
|
export import MediaParser = InlineParser.MediaParser;
|
|
42
42
|
export import HTMLEntityParser = InlineParser.HTMLEntityParser;
|
|
43
43
|
export import UnsafeHTMLEntityParser = InlineParser.UnsafeHTMLEntityParser;
|
|
44
|
-
export import
|
|
44
|
+
export import ShortMediaParser = InlineParser.ShortMediaParser;
|
|
45
45
|
export import AutolinkParser = InlineParser.AutolinkParser;
|
|
46
46
|
export import BracketParser = InlineParser.BracketParser;
|
|
47
47
|
|
|
@@ -53,8 +53,9 @@ export const inline: InlineParser = union([
|
|
|
53
53
|
math,
|
|
54
54
|
extension,
|
|
55
55
|
ruby,
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
textlink,
|
|
57
|
+
linemedialink,
|
|
58
|
+
linemedia,
|
|
58
59
|
html,
|
|
59
60
|
insertion,
|
|
60
61
|
deletion,
|
|
@@ -63,7 +64,7 @@ export const inline: InlineParser = union([
|
|
|
63
64
|
emphasis,
|
|
64
65
|
code,
|
|
65
66
|
htmlentity,
|
|
66
|
-
|
|
67
|
+
lineshortmedia,
|
|
67
68
|
autolink,
|
|
68
69
|
bracket,
|
|
69
70
|
text
|
|
@@ -4,7 +4,7 @@ import { nonWhitespace } from './text';
|
|
|
4
4
|
|
|
5
5
|
const delimiter = /[\s\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/;
|
|
6
6
|
|
|
7
|
-
export const escsource: EscapableSourceParser = creation(1, false, ({ source }) => {
|
|
7
|
+
export const escsource: EscapableSourceParser = creation(1, false, ({ source, context }) => {
|
|
8
8
|
if (source === '') return;
|
|
9
9
|
const i = source.search(delimiter);
|
|
10
10
|
switch (i) {
|
|
@@ -12,6 +12,10 @@ export const escsource: EscapableSourceParser = creation(1, false, ({ source })
|
|
|
12
12
|
return [[source], ''];
|
|
13
13
|
case 0:
|
|
14
14
|
switch (source[0]) {
|
|
15
|
+
case '\r':
|
|
16
|
+
assert(!source.includes('\r', 1));
|
|
17
|
+
context.resources && ++context.resources.clock;
|
|
18
|
+
return [[], source.slice(1)];
|
|
15
19
|
case '\x1B':
|
|
16
20
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
17
21
|
case '\\':
|
|
@@ -16,6 +16,10 @@ export const text: TextParser = creation(1, false, ({ source, context }) => {
|
|
|
16
16
|
return [[source], ''];
|
|
17
17
|
case 0:
|
|
18
18
|
switch (source[0]) {
|
|
19
|
+
case '\r':
|
|
20
|
+
assert(!source.includes('\r', 1));
|
|
21
|
+
context.resources && ++context.resources.clock;
|
|
22
|
+
return [[], source.slice(1)];
|
|
19
23
|
case '\x1B':
|
|
20
24
|
case '\\':
|
|
21
25
|
switch (source[1]) {
|
|
@@ -60,7 +64,7 @@ export const txt: TxtParser = union([
|
|
|
60
64
|
text,
|
|
61
65
|
]) as TxtParser;
|
|
62
66
|
|
|
63
|
-
export const linebreak: LinebreakParser = focus(
|
|
67
|
+
export const linebreak: LinebreakParser = focus(/^[\r\n]/, union([
|
|
64
68
|
text,
|
|
65
69
|
])) as LinebreakParser;
|
|
66
70
|
|
|
@@ -2,7 +2,7 @@ import { UnescapableSourceParser } from '../source';
|
|
|
2
2
|
import { creation } from '../../combinator';
|
|
3
3
|
import { delimiter, nonWhitespace, nonAlphanumeric, isAlphanumeric } from './text';
|
|
4
4
|
|
|
5
|
-
export const unescsource: UnescapableSourceParser = creation(1, false, ({ source }) => {
|
|
5
|
+
export const unescsource: UnescapableSourceParser = creation(1, false, ({ source, context }) => {
|
|
6
6
|
assert(source[0] !== '\x1B');
|
|
7
7
|
if (source === '') return;
|
|
8
8
|
const i = source.search(delimiter);
|
|
@@ -10,6 +10,12 @@ export const unescsource: UnescapableSourceParser = creation(1, false, ({ source
|
|
|
10
10
|
case -1:
|
|
11
11
|
return [[source], ''];
|
|
12
12
|
case 0: {
|
|
13
|
+
switch (source[0]) {
|
|
14
|
+
case '\r':
|
|
15
|
+
assert(!source.includes('\r', 1));
|
|
16
|
+
context.resources && ++context.resources.clock;
|
|
17
|
+
return [[], source.slice(1)];
|
|
18
|
+
}
|
|
13
19
|
const b = source[0] !== '\n' && source[0].trimStart() === '';
|
|
14
20
|
const i = b || isAlphanumeric(source[0])
|
|
15
21
|
? source.search(b ? nonWhitespace : nonAlphanumeric) || 1
|
package/src/parser/util.ts
CHANGED
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
import { Parser } from '../combinator/data/parser';
|
|
2
|
-
import { convert } from '../combinator';
|
|
3
|
-
|
|
4
|
-
export function format<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
5
|
-
export function format<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
6
|
-
return convert(
|
|
7
|
-
source => source.replace(/(?<=^!?)https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=[^\S\n]*(?:$|\n))/gm, '{ $& }'),
|
|
8
|
-
parser);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
1
|
export function stringify(nodes: readonly (HTMLElement | string)[]): string {
|
|
12
2
|
let acc = '';
|
|
13
3
|
for (let i = 0; i < nodes.length; ++i) {
|
package/src/parser/visibility.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { union, some, verify, convert, fmap } from '../combinator';
|
|
|
4
4
|
import { unsafehtmlentity } from './inline/htmlentity';
|
|
5
5
|
import { linebreak, unescsource } from './source';
|
|
6
6
|
import { State } from './context';
|
|
7
|
-
import { format } from './util';
|
|
8
7
|
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
9
8
|
import { reduce } from 'spica/memoize';
|
|
10
9
|
import { push } from 'spica/array';
|
|
@@ -17,7 +16,7 @@ export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Pa
|
|
|
17
16
|
return union([
|
|
18
17
|
convert(
|
|
19
18
|
source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')),
|
|
20
|
-
verify(
|
|
19
|
+
verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
|
|
21
20
|
some(union([linebreak, unescsource])),
|
|
22
21
|
]);
|
|
23
22
|
}
|
package/src/util/quote.test.ts
CHANGED
|
@@ -5,10 +5,10 @@ describe('Unit: util/quote', () => {
|
|
|
5
5
|
describe('quote', () => {
|
|
6
6
|
it('basic', () => {
|
|
7
7
|
const range = document.createRange();
|
|
8
|
-
const el = parse('>>1\n>2\n> a\n>>4 `b` ${c}
|
|
8
|
+
const el = parse('>>1\n>2\n> a\n>>4 `b` ${c}$\n!{d}\n [e](f) ').firstElementChild!;
|
|
9
9
|
range.setStart(el.firstChild!.firstChild!, 0);
|
|
10
10
|
range.setEnd(el.lastChild!.lastChild!.lastChild!, 1);
|
|
11
|
-
assert(quote('3', range) === `>>>1\n> >2\n>> a\n>>3\n> >>4 \`b\` \${c}
|
|
11
|
+
assert(quote('3', range) === `>>>1\n> >2\n>> a\n>>3\n> >>4 \`b\` \${c}$\n> !{d}\n> e`);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('adjustment', () => {
|