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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.269.0
4
+
5
+ - Change media syntax to line-level syntax.
6
+
3
7
  ## 0.268.2
4
8
 
5
9
  - Refactoring.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.268.2 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
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.lineurl = exports.autolink = void 0;
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
- const util_1 = __webpack_require__(9437);
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.line)((0, combinator_1.subsequence)([autolink_2.lineurl, (0, combinator_1.some)((0, combinator_1.union)([math_1.math, autolink_1.autolink, source_1.linebreak, source_1.unescsource]))])));
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.link, media_1.media, 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.shortmedia, autolink_1.autolink, bracket_1.bracket, source_1.text]);
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.fmap)((0, combinator_1.validate)(/^(?:[@#>0-9a-z]|\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.some)((0, combinator_1.union)([url_1.url, email_1.email,
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]))))), ns => ns.length === 1 ? ns : [(0, util_1.stringify)(ns)]);
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
- const 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) => {
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
- const 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)))));
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)('\n', (0, combinator_1.union)([exports.text]));
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, __webpack_require__) => {
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 = exports.format = void 0;
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)((0, util_1.format)(parser), (ns, rest, context) => !rest && hasVisible(ns, context))), (0, combinator_1.some)((0, combinator_1.union)([source_1.linebreak, source_1.unescsource]))]);
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.ShortmediaParser,
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
- AutolinkParser.LineUrlParser,
602
- Parser<string | HTMLElement, Context, [
603
- InlineParser.MathParser,
604
- InlineParser.AutolinkParser,
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.MediaParser,
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.ShortmediaParser,
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
- ShortmediaParser,
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
- ShortmediaParser,
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 ShortmediaParser extends
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
- AutolinkParser.UrlParser,
1074
- AutolinkParser.EmailParser,
1075
- SourceParser.StrParser,
1076
- AutolinkParser.ChannelParser,
1077
- AutolinkParser.AccountParser,
1078
- SourceParser.StrParser,
1079
- SourceParser.StrParser,
1080
- AutolinkParser.HashtagParser,
1081
- AutolinkParser.HashnumParser,
1082
- SourceParser.StrParser,
1083
- SourceParser.StrParser,
1084
- AutolinkParser.AnchorParser,
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.LineUrlParser,
1180
- Parser<string | HTMLElement, Context, [
1181
- InlineParser.AutolinkParser,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.268.2",
3
+ "version": "0.269.0",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -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(' 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>'], '']);
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>'], '']);
@@ -1,21 +1,14 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
- import { union, tails, subsequence, some, line, focus, lazy } from '../combinator';
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, str } from './source';
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(() => some(line(subsequence([
11
- lineurl,
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#!')), [['<p><a class="url" href="http://host#!" target="_blank">http://host#!</a></p>'], '']);
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#!')), [['<p><a href="http://host#!" target="_blank"><img class="media" data-src="http://host#!" alt=""></a></p>'], '']);
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
- visualize(trimEnd(some(union([inline])))),
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">&gt; $-a, $-b</span>', '<br>'], '']);
56
56
  assert.deepStrictEqual(inspect(parser('> $a=b$')), [['<span class="quote">&gt; <span class="math" translate="no" data-src="$a=b$">$a=b$</span></span>', '<br>'], '']);
57
57
  assert.deepStrictEqual(inspect(parser('> ${a}$')), [['<span class="quote">&gt; <span class="math" translate="no" data-src="${a}$">${a}$</span></span>', '<br>'], '']);
58
- assert.deepStrictEqual(inspect(parser('> http://host#!')), [['<span class="quote">&gt; <a class="url" href="http://host#!" target="_blank">http://host#!</a></span>', '<br>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('> http://host#\\')), [['<span class="quote">&gt; <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">&gt; a<br>&gt; <a class="url" href="http://host#\\" target="_blank">http://host#\\</a> <br>&gt; b</span>', '<br>'], '']);
60
- assert.deepStrictEqual(inspect(parser('> !http://host#!')), [['<span class="quote">&gt; !<a class="url" href="http://host#!" target="_blank">http://host#!</a></span>', '<br>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('> !http://host#\\')), [['<span class="quote">&gt; !<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, subsequence, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
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, context }), []);
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(line(subsequence([
76
- lineurl,
77
- some(union([
78
- math, // quote補助関数が残した数式をパースする。他の構文で数式を残す場合はソーステキストを直接使用する。
79
- autolink,
80
- linebreak,
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 = fmap(
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
- some(union([
19
- url,
20
- email,
21
- // Escape unmatched email-like strings.
22
- focus(
23
- /^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i,
24
- ({ source }) => {
25
- if (source.length > 255 || source.includes('@')) return [[source], ''];
26
- const i = source.indexOf('_');
27
- if (i === -1) return [[source], ''];
28
- return [[source.slice(0, i)], source.slice(i)];
29
- }),
30
- channel,
31
- account,
32
- // Escape unmatched account-like strings.
33
- str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
34
- // Escape invalid leading characters.
35
- str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
36
- hashtag,
37
- hashnum,
38
- // Escape unmatched hashtag-like strings.
39
- str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
40
- // Escape invalid leading characters.
41
- str(/^[0-9\p{Sc}](?=>)/u),
42
- anchor,
43
- ]))))),
44
- ns => ns.length === 1 ? ns : [stringify(ns)]);
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"><a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a></span>'], '']);
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 { ShortmediaParser } from '../inline';
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: ShortmediaParser = rewrite(
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 href="a" target="_blank"><img class="media" data-src="a" alt=""></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"><img class="media" data-src="http://host" alt=""></a>'], '']);
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>'], '']);
@@ -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 { link } from './inline/link';
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 { media } from './inline/media';
18
+ import { linemedia } from './inline/media';
19
19
  import { htmlentity } from './inline/htmlentity';
20
- import { shortmedia } from './inline/shortmedia';
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 ShortmediaParser = InlineParser.ShortmediaParser;
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
- link,
57
- media,
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
- shortmedia,
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('\n', union([
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
@@ -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) {
@@ -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(format(parser), (ns, rest, context) => !rest && hasVisible(ns, context))),
19
+ verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
21
20
  some(union([linebreak, unescsource])),
22
21
  ]);
23
22
  }
@@ -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}$ !{d}\n [e](f) ').firstElementChild!;
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}$ !{d}\n> e`);
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', () => {