securemark 0.267.0 → 0.268.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.268.0
4
+
5
+ - Add lineurl syntax.
6
+
3
7
  ## 0.267.0
4
8
 
5
9
  - Change horizontalrule syntax to pagebreak syntax.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.267.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.268.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"));
@@ -2653,7 +2653,7 @@ function block(parser, separation = true) {
2653
2653
  });
2654
2654
  if (result === undefined) return;
2655
2655
  const rest = (0, parser_1.exec)(result);
2656
- if (separation && !(0, line_1.isEmpty)((0, line_1.firstline)(rest))) return;
2656
+ if (separation && !(0, line_1.isBlank)((0, line_1.firstline)(rest))) return;
2657
2657
  return rest === '' || source[source.length - rest.length - 1] === '\n' ? result : undefined;
2658
2658
  };
2659
2659
  }
@@ -2721,7 +2721,7 @@ exports.verify = verify;
2721
2721
  Object.defineProperty(exports, "__esModule", ({
2722
2722
  value: true
2723
2723
  }));
2724
- exports.isEmpty = exports.firstline = exports.line = void 0;
2724
+ exports.isBlank = exports.firstline = exports.line = void 0;
2725
2725
  const parser_1 = __webpack_require__(6728);
2726
2726
  const memo_1 = __webpack_require__(1090);
2727
2727
  function line(parser) {
@@ -2740,7 +2740,7 @@ function line(parser) {
2740
2740
  });
2741
2741
  context.offset -= source.length - line.length;
2742
2742
  if (result === undefined) return;
2743
- return isEmpty((0, parser_1.exec)(result)) ? [(0, parser_1.eval)(result), source.slice(line.length)] : undefined;
2743
+ return isBlank((0, parser_1.exec)(result)) ? [(0, parser_1.eval)(result), source.slice(line.length)] : undefined;
2744
2744
  };
2745
2745
  }
2746
2746
  exports.line = line;
@@ -2756,10 +2756,10 @@ function firstline(source) {
2756
2756
  }
2757
2757
  }
2758
2758
  exports.firstline = firstline;
2759
- function isEmpty(line) {
2759
+ function isBlank(line) {
2760
2760
  return line === '' || line === '\n' || line.trimStart() === '';
2761
2761
  }
2762
- exports.isEmpty = isEmpty;
2762
+ exports.isBlank = isBlank;
2763
2763
 
2764
2764
  /***/ }),
2765
2765
 
@@ -2855,20 +2855,20 @@ function fence(opener, limit, separation = true) {
2855
2855
  if (matches[0].indexOf(delim, delim.length) !== -1) return;
2856
2856
  let rest = source.slice(matches[0].length);
2857
2857
  // Prevent annoying parsing in editing.
2858
- if ((0, line_1.isEmpty)((0, line_1.firstline)(rest)) && (0, line_1.firstline)(rest.slice((0, line_1.firstline)(rest).length)).trimEnd() !== delim) return;
2858
+ if ((0, line_1.isBlank)((0, line_1.firstline)(rest)) && (0, line_1.firstline)(rest.slice((0, line_1.firstline)(rest).length)).trimEnd() !== delim) return;
2859
2859
  let block = '';
2860
2860
  let closer = '';
2861
2861
  let overflow = '';
2862
2862
  for (let count = 1;; ++count) {
2863
2863
  if (rest === '') break;
2864
2864
  const line = (0, line_1.firstline)(rest);
2865
- if ((closer || count > limit + 1) && (0, line_1.isEmpty)(line)) break;
2865
+ if ((closer || count > limit + 1) && (0, line_1.isBlank)(line)) break;
2866
2866
  if (closer) {
2867
2867
  overflow += line;
2868
2868
  }
2869
2869
  if (!closer && count <= limit + 1 && line.slice(0, delim.length) === delim && line.trimEnd() === delim) {
2870
2870
  closer = line;
2871
- if ((0, line_1.isEmpty)((0, line_1.firstline)(rest.slice(line.length)))) {
2871
+ if ((0, line_1.isBlank)((0, line_1.firstline)(rest.slice(line.length)))) {
2872
2872
  rest = rest.slice(line.length);
2873
2873
  break;
2874
2874
  }
@@ -3908,7 +3908,7 @@ function bind(target, settings) {
3908
3908
  })
3909
3909
  };
3910
3910
 
3911
- if (context.id?.match(/[^0-9a-z-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
3911
+ if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
3912
3912
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
3913
3913
  const blocks = [];
3914
3914
  const adds = [];
@@ -4241,7 +4241,7 @@ function parse(source, opts = {}, context) {
4241
4241
  })
4242
4242
  };
4243
4243
 
4244
- if (context.id?.match(/[^0-9a-z-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4244
+ if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4245
4245
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
4246
4246
  const node = (0, dom_1.frag)();
4247
4247
  let index = 0;
@@ -4274,31 +4274,14 @@ exports.parse = parse;
4274
4274
  Object.defineProperty(exports, "__esModule", ({
4275
4275
  value: true
4276
4276
  }));
4277
- exports.autolink = void 0;
4277
+ exports.lineurl = exports.autolink = void 0;
4278
4278
  const combinator_1 = __webpack_require__(2087);
4279
+ const link_1 = __webpack_require__(9628);
4279
4280
  const autolink_1 = __webpack_require__(6051);
4280
4281
  const source_1 = __webpack_require__(6743);
4281
- const delimiter = /[@#>0-9A-Za-z\n]|\S[#>]/;
4282
- const autolink = ({
4283
- source,
4284
- context
4285
- }) => {
4286
- if (source === '') return;
4287
- const i = source.search(delimiter);
4288
- switch (i) {
4289
- case -1:
4290
- return [[source], ''];
4291
- case 0:
4292
- return parser({
4293
- source,
4294
- context
4295
- });
4296
- default:
4297
- return [[source.slice(0, i)], source.slice(i)];
4298
- }
4299
- };
4300
- exports.autolink = autolink;
4301
- const parser = (0, combinator_1.lazy)(() => (0, combinator_1.union)([autolink_1.autolink, source_1.linebreak, source_1.unescsource]));
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]))));
4302
4285
 
4303
4286
  /***/ }),
4304
4287
 
@@ -4377,7 +4360,7 @@ exports.blockquote = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, co
4377
4360
  const opener = /^(?=>>+(?:$|\s))/;
4378
4361
  const indent = (0, combinator_1.block)((0, combinator_1.open)(opener, (0, combinator_1.some)(source_1.contentline, /^>(?:$|\s)/)), false);
4379
4362
  const unindent = source => source.replace(/(?<=^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '');
4380
- const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)((0, combinator_1.some)(autolink_1.autolink), ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
4363
+ const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)(autolink_1.autolink, ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
4381
4364
  const markdown = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, markdown)), (0, combinator_1.creation)(99, false, (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, ({
4382
4365
  source,
4383
4366
  context
@@ -4450,7 +4433,7 @@ exports.codeblock = (0, combinator_1.block)((0, combinator_1.validate)('```', (0
4450
4433
  'data-lang': params.lang || undefined,
4451
4434
  'data-line': params.line || undefined,
4452
4435
  'data-path': params.path || undefined
4453
- }, params.lang ? context.caches?.code?.get(`${params.lang ?? ''}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes || body.slice(0, -1) || undefined : (0, dom_1.defrag)((0, parser_1.eval)((0, combinator_1.some)(autolink_1.autolink)({
4436
+ }, params.lang ? context.caches?.code?.get(`${params.lang ?? ''}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes || body.slice(0, -1) || undefined : (0, dom_1.defrag)((0, parser_1.eval)((0, autolink_1.autolink)({
4454
4437
  source: body.slice(0, -1),
4455
4438
  context
4456
4439
  }), [])));
@@ -5252,7 +5235,7 @@ const openers = {
5252
5235
  };
5253
5236
  exports.olist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.validate)(new RegExp([/^([0-9]+|[a-z]+|[A-Z]+)(?:-[0-9]+)*\.(?=[^\S\n]|\n[^\S\n]*\S)/.source, /^\(([0-9]+|[a-z]+)\)(?:-[0-9]+)*(?=[^\S\n]|\n[^\S\n]*\S)/.source].join('|')), (0, combinator_1.state)(8 /* State.media */, exports.olist_))));
5254
5237
  exports.olist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.match)(openers['.'], (0, memoize_1.memoize)(ms => list(type(ms[1]), '.'), ms => type(ms[1]).charCodeAt(0) || 0, [])), (0, combinator_1.match)(openers['('], (0, memoize_1.memoize)(ms => list(type(ms[1]), '('), ms => type(ms[1]).charCodeAt(0) || 0, []))])));
5255
- const list = (type, form) => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(heads[form], (0, combinator_1.subsequence)([ulist_1.checkbox, (0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline])))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([ulist_1.ulist_, exports.olist_, ilist_1.ilist_]))]), exports.invalid), ns => [(0, dom_1.html)('li', {
5238
+ const list = (type, form) => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(heads[form], (0, combinator_1.subsequence)([ulist_1.checkbox, (0, visibility_1.trimBlank)((0, visibility_1.visualize)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline]))))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([ulist_1.ulist_, exports.olist_, ilist_1.ilist_]))]), exports.invalid), ns => [(0, dom_1.html)('li', {
5256
5239
  'data-marker': ns[0] || undefined
5257
5240
  }, (0, dom_1.defrag)((0, ulist_1.fillFirstLine)((0, array_1.shift)(ns)[1])))]), true)]))), es => [format((0, dom_1.html)('ol', es), type, form)]);
5258
5241
  const heads = {
@@ -5425,9 +5408,7 @@ exports.cite = (0, combinator_1.creation)(1, false, (0, combinator_1.line)((0, c
5425
5408
  source
5426
5409
  }) => [[(0, dom_1.html)('a', {
5427
5410
  class: 'anchor'
5428
- }, source)], '']),
5429
- // Support all domains, but don't support IP(v6) addresses.
5430
- (0, combinator_1.focus)(/^>>https?:\/\/[^\p{C}\p{S}\p{P}\s]\S*(?=\s*$)/u, ({
5411
+ }, source)], '']), (0, combinator_1.focus)(/^>>https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=\s*$)/u, ({
5431
5412
  source
5432
5413
  }) => [[(0, dom_1.html)('a', {
5433
5414
  class: 'anchor',
@@ -5454,8 +5435,9 @@ exports.quote = exports.syntax = void 0;
5454
5435
  const parser_1 = __webpack_require__(6728);
5455
5436
  const combinator_1 = __webpack_require__(2087);
5456
5437
  const math_1 = __webpack_require__(8946);
5438
+ const autolink_1 = __webpack_require__(6051);
5457
5439
  const source_1 = __webpack_require__(6743);
5458
- const autolink_1 = __webpack_require__(7185);
5440
+ const autolink_2 = __webpack_require__(7185);
5459
5441
  const dom_1 = __webpack_require__(3252);
5460
5442
  exports.syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
5461
5443
  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 ? {
@@ -5473,8 +5455,8 @@ const qblock = ({
5473
5455
  source = source.replace(/\n$/, '');
5474
5456
  const lines = source.match(/^.*\n?/mg);
5475
5457
  const quotes = source.match(/^>+[^\S\n]/mg);
5476
- const content = lines.reduce((acc, line, row) => acc + line.slice(quotes[row].length), '');
5477
- const nodes = (0, parser_1.eval)((0, combinator_1.some)(text)({
5458
+ const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
5459
+ const nodes = (0, parser_1.eval)(text({
5478
5460
  source: content,
5479
5461
  context
5480
5462
  }), []);
@@ -5501,7 +5483,7 @@ const qblock = ({
5501
5483
  nodes.unshift('');
5502
5484
  return [nodes, ''];
5503
5485
  };
5504
- const text = (0, combinator_1.union)([math_1.math, autolink_1.autolink]);
5486
+ 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]))])));
5505
5487
 
5506
5488
  /***/ }),
5507
5489
 
@@ -5527,7 +5509,7 @@ exports.sidefence = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, com
5527
5509
  })])));
5528
5510
  const opener = /^(?=\|\|+(?:$|\s))/;
5529
5511
  const unindent = source => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
5530
- const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.focus)(/^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)((0, combinator_1.some)(autolink_1.autolink), ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
5512
+ const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, combinator_1.focus)(/^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)(autolink_1.autolink, ns => [(0, dom_1.html)('pre', (0, dom_1.defrag)(ns))])))]))), ns => [(0, dom_1.html)('blockquote', ns)]));
5531
5513
 
5532
5514
  /***/ }),
5533
5515
 
@@ -5595,7 +5577,7 @@ const visibility_1 = __webpack_require__(7618);
5595
5577
  const array_1 = __webpack_require__(8112);
5596
5578
  const dom_1 = __webpack_require__(3252);
5597
5579
  exports.ulist = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.validate)(/^-(?=[^\S\n]|\n[^\S\n]*\S)/, (0, combinator_1.state)(8 /* State.media */, exports.ulist_))));
5598
- exports.ulist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)(/^-(?=$|\s)/, (0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(/^-(?:$|\s)/, (0, combinator_1.subsequence)([exports.checkbox, (0, visibility_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline])))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([exports.ulist_, olist_1.olist_, ilist_1.ilist_]))]), olist_1.invalid), ns => [(0, dom_1.html)('li', (0, dom_1.defrag)(fillFirstLine(ns)))]), true)])))), es => [format((0, dom_1.html)('ul', es))])));
5580
+ exports.ulist_ = (0, combinator_1.lazy)(() => (0, combinator_1.block)((0, combinator_1.fmap)((0, combinator_1.validate)(/^-(?=$|\s)/, (0, combinator_1.some)((0, combinator_1.creation)(1, false, (0, combinator_1.union)([(0, inline_1.indexee)((0, combinator_1.fmap)((0, combinator_1.fallback)((0, combinator_1.inits)([(0, combinator_1.line)((0, combinator_1.open)(/^-(?:$|\s)/, (0, combinator_1.subsequence)([exports.checkbox, (0, visibility_1.trimBlank)((0, visibility_1.visualize)((0, combinator_1.some)((0, combinator_1.union)([inline_1.indexer, inline_1.inline]))))]), true)), (0, combinator_1.indent)((0, combinator_1.union)([exports.ulist_, olist_1.olist_, ilist_1.ilist_]))]), olist_1.invalid), ns => [(0, dom_1.html)('li', (0, dom_1.defrag)(fillFirstLine(ns)))]), true)])))), es => [format((0, dom_1.html)('ul', es))])));
5599
5581
  exports.checkbox = (0, combinator_1.creation)(1, false, (0, combinator_1.focus)(/^\[[xX ]\](?=$|\s)/, ({
5600
5582
  source
5601
5583
  }) => [[(0, dom_1.html)('span', {
@@ -6099,7 +6081,7 @@ const indexee_1 = __webpack_require__(1269);
6099
6081
  const source_1 = __webpack_require__(6743);
6100
6082
  const visibility_1 = __webpack_require__(7618);
6101
6083
  const dom_1 = __webpack_require__(3252);
6102
- exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.constraint)(64 /* State.index */, false, (0, combinator_1.syntax)(128 /* Syntax.index */, 2, 1, 502 /* State.linkers */ | 8 /* State.media */, (0, visibility_1.startTight)((0, combinator_1.open)((0, source_1.stropt)(/^\|?/), (0, visibility_1.trimBlankEnd)((0, combinator_1.some)((0, combinator_1.union)([signature, inline_1.inline]), ']', [[/^\\?\n/, 9], [']', 2]])), true)))), ']', false, ([, ns], rest) => [[(0, dom_1.html)('a', (0, dom_1.defrag)(ns))], rest])), ([el]) => [(0, dom_1.define)(el, {
6084
+ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.constraint)(64 /* State.index */, false, (0, combinator_1.syntax)(128 /* Syntax.index */, 2, 1, 502 /* State.linkers */ | 8 /* State.media */, (0, visibility_1.startTight)((0, combinator_1.open)((0, source_1.stropt)('|'), (0, visibility_1.trimBlankEnd)((0, combinator_1.some)((0, combinator_1.union)([signature, inline_1.inline]), ']', [[/^\\?\n/, 9], [']', 2]])), true)))), ']', false, ([, ns], rest) => [[(0, dom_1.html)('a', (0, dom_1.defrag)(ns))], rest])), ([el]) => [(0, dom_1.define)(el, {
6103
6085
  id: el.id ? null : undefined,
6104
6086
  class: 'index',
6105
6087
  href: el.id ? `#${el.id}` : undefined
@@ -7376,8 +7358,8 @@ Object.defineProperty(exports, "__esModule", ({
7376
7358
  exports.contentline = exports.emptyline = exports.anyline = void 0;
7377
7359
  const combinator_1 = __webpack_require__(2087);
7378
7360
  exports.anyline = (0, combinator_1.line)(() => [[], '']);
7379
- exports.emptyline = (0, combinator_1.line)(i => (0, combinator_1.isEmpty)(i.source) ? [[], ''] : undefined);
7380
- exports.contentline = (0, combinator_1.line)(i => !(0, combinator_1.isEmpty)(i.source) ? [[], ''] : undefined);
7361
+ exports.emptyline = (0, combinator_1.line)(i => (0, combinator_1.isBlank)(i.source) ? [[], ''] : undefined);
7362
+ exports.contentline = (0, combinator_1.line)(i => !(0, combinator_1.isBlank)(i.source) ? [[], ''] : undefined);
7381
7363
 
7382
7364
  /***/ }),
7383
7365
 
@@ -7414,7 +7396,7 @@ function stropt(pattern) {
7414
7396
  source
7415
7397
  }) => {
7416
7398
  if (source === '') return;
7417
- return source.slice(0, pattern.length) === pattern ? [[pattern], source.slice(pattern.length)] : undefined;
7399
+ return source.slice(0, pattern.length) === pattern ? [[pattern], source.slice(pattern.length)] : [[''], source];
7418
7400
  }) : (0, combinator_1.creation)(1, false, ({
7419
7401
  source
7420
7402
  }) => {
@@ -7529,7 +7511,7 @@ exports.unescsource = (0, combinator_1.creation)(1, false, ({
7529
7511
  /***/ }),
7530
7512
 
7531
7513
  /***/ 9437:
7532
- /***/ ((__unused_webpack_module, exports) => {
7514
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
7533
7515
 
7534
7516
  "use strict";
7535
7517
 
@@ -7537,7 +7519,12 @@ exports.unescsource = (0, combinator_1.creation)(1, false, ({
7537
7519
  Object.defineProperty(exports, "__esModule", ({
7538
7520
  value: true
7539
7521
  }));
7540
- exports.stringify = void 0;
7522
+ exports.stringify = exports.format = void 0;
7523
+ const combinator_1 = __webpack_require__(2087);
7524
+ function format(parser) {
7525
+ return (0, combinator_1.convert)(source => source.replace(/(?<=^!?)https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=[^\S\n]*(?:$|\n))/gm, '{ $& }'), parser);
7526
+ }
7527
+ exports.format = format;
7541
7528
  function stringify(nodes) {
7542
7529
  let acc = '';
7543
7530
  for (let i = 0; i < nodes.length; ++i) {
@@ -7569,12 +7556,13 @@ const parser_1 = __webpack_require__(6728);
7569
7556
  const combinator_1 = __webpack_require__(2087);
7570
7557
  const htmlentity_1 = __webpack_require__(1562);
7571
7558
  const source_1 = __webpack_require__(6743);
7559
+ const util_1 = __webpack_require__(9437);
7572
7560
  const normalize_1 = __webpack_require__(185);
7573
7561
  const memoize_1 = __webpack_require__(1808);
7574
7562
  const array_1 = __webpack_require__(8112);
7575
7563
  function visualize(parser) {
7576
7564
  const blankline = new RegExp(/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr[^\S\n]*>)+$/.source.replace('IHN', `(?:${normalize_1.invisibleHTMLEntityNames.join('|')})`), 'gm');
7577
- 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]))]);
7565
+ 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]))]);
7578
7566
  }
7579
7567
  exports.visualize = visualize;
7580
7568
  function hasVisible(nodes, {
@@ -8201,7 +8189,7 @@ Object.defineProperty(exports, "__esModule", ({
8201
8189
  exports.quote = void 0;
8202
8190
  const parser_1 = __webpack_require__(6728);
8203
8191
  const cite_1 = __webpack_require__(6315);
8204
- const dom_1 = __webpack_require__(3252);
8192
+ //import { url } from '../parser/inline/autolink/url';
8205
8193
  function quote(anchor, range) {
8206
8194
  if ((0, parser_1.exec)((0, cite_1.cite)({
8207
8195
  source: `>>${anchor}`,
@@ -8215,8 +8203,15 @@ function quote(anchor, range) {
8215
8203
  switch (true) {
8216
8204
  case el.matches('code'):
8217
8205
  case el.matches('.math'):
8218
- (0, dom_1.define)(el, el.getAttribute('data-src'));
8206
+ el.replaceWith(el.getAttribute('data-src'));
8219
8207
  continue;
8208
+ //case el.matches('.url'):
8209
+ // if (exec(url({ source: el.getAttribute('href')!, context: {} })) === '') continue;
8210
+ // el.replaceWith(
8211
+ // /[\s{}]/.test(el.getAttribute('href')!)
8212
+ // ? `{ ${el.getAttribute('href')} }`
8213
+ // : `{${el.getAttribute('href')}}`);
8214
+ // continue;
8220
8215
  case el.matches('.media'):
8221
8216
  el.replaceWith(/[\s{}]/.test(el.getAttribute('data-src')) ? `!{ ${el.getAttribute('data-src')} }` : `!{${el.getAttribute('data-src')}}`);
8222
8217
  continue;
package/markdown.d.ts CHANGED
@@ -598,8 +598,13 @@ export namespace MarkdownParser {
598
598
  export interface TextParser extends
599
599
  Block<'reply/quote/text'>,
600
600
  Parser<string | HTMLElement, Context, [
601
- InlineParser.MathParser,
602
- AutolinkParser,
601
+ AutolinkParser.LineUrlParser,
602
+ Parser<string | HTMLElement, Context, [
603
+ InlineParser.MathParser,
604
+ InlineParser.AutolinkParser,
605
+ SourceParser.LinebreakParser,
606
+ SourceParser.UnescapableSourceParser,
607
+ ]>,
603
608
  ]> {
604
609
  }
605
610
  export interface PlaceholderParser extends
@@ -1171,11 +1176,23 @@ export namespace MarkdownParser {
1171
1176
  export interface AutolinkParser extends
1172
1177
  Markdown<'autolink'>,
1173
1178
  Parser<string | HTMLElement, Context, [
1174
- InlineParser.AutolinkParser,
1175
- SourceParser.LinebreakParser,
1176
- SourceParser.UnescapableSourceParser,
1179
+ AutolinkParser.LineUrlParser,
1180
+ Parser<string | HTMLElement, Context, [
1181
+ InlineParser.AutolinkParser,
1182
+ SourceParser.LinebreakParser,
1183
+ SourceParser.UnescapableSourceParser,
1184
+ ]>,
1177
1185
  ]> {
1178
1186
  }
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
+ }
1179
1196
  export namespace SourceParser {
1180
1197
  interface Source<T extends string> extends Markdown<`source/${T}`> { }
1181
1198
  export interface TextParser extends
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.267.0",
3
+ "version": "0.268.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",
@@ -34,13 +34,13 @@
34
34
  "@types/mocha": "10.0.1",
35
35
  "@types/power-assert": "1.5.8",
36
36
  "@types/prismjs": "1.26.0",
37
- "@typescript-eslint/parser": "^5.49.0",
37
+ "@typescript-eslint/parser": "^5.52.0",
38
38
  "babel-loader": "^9.1.2",
39
39
  "babel-plugin-unassert": "^3.2.0",
40
40
  "concurrently": "^7.6.0",
41
- "eslint": "^8.32.0",
42
- "eslint-plugin-redos": "^4.4.3",
43
- "eslint-webpack-plugin": "^3.2.0",
41
+ "eslint": "^8.34.0",
42
+ "eslint-plugin-redos": "^4.4.5",
43
+ "eslint-webpack-plugin": "^4.0.0",
44
44
  "glob": "^8.1.0",
45
45
  "karma": "^6.4.1",
46
46
  "karma-chrome-launcher": "^3.1.1",
@@ -49,12 +49,12 @@
49
49
  "karma-mocha": "^2.0.1",
50
50
  "karma-power-assert": "^1.0.0",
51
51
  "mocha": "^10.2.0",
52
- "npm-check-updates": "^16.6.3",
52
+ "npm-check-updates": "^16.7.4",
53
53
  "semver": "^7.3.8",
54
54
  "spica": "0.0.719",
55
55
  "ts-loader": "^9.4.2",
56
56
  "typed-dom": "^0.0.315",
57
- "typescript": "4.9.4",
57
+ "typescript": "4.9.5",
58
58
  "webpack": "^5.75.0",
59
59
  "webpack-cli": "^5.0.1",
60
60
  "webpack-merge": "^5.8.0"
@@ -1,6 +1,6 @@
1
1
  import { Parser, exec } from '../../data/parser';
2
2
  import { Memo } from '../../data/parser/context/memo';
3
- import { firstline, isEmpty } from './line';
3
+ import { firstline, isBlank } from './line';
4
4
 
5
5
  export function block<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
6
6
  export function block<T>(parser: Parser<T>, separation = true): Parser<T> {
@@ -11,7 +11,7 @@ export function block<T>(parser: Parser<T>, separation = true): Parser<T> {
11
11
  const result = parser({ source, context });
12
12
  if (result === undefined) return;
13
13
  const rest = exec(result);
14
- if (separation && !isEmpty(firstline(rest))) return;
14
+ if (separation && !isBlank(firstline(rest))) return;
15
15
  assert(rest === '' || source[source.length - rest.length - 1] === '\n');
16
16
  return rest === '' || source[source.length - rest.length - 1] === '\n'
17
17
  ? result
@@ -14,7 +14,7 @@ export function line<T>(parser: Parser<T>): Parser<T> {
14
14
  assert(check(line, result));
15
15
  context.offset -= source.length - line.length;
16
16
  if (result === undefined) return;
17
- return isEmpty(exec(result))
17
+ return isBlank(exec(result))
18
18
  ? [eval(result), source.slice(line.length)]
19
19
  : undefined;
20
20
  };
@@ -32,7 +32,7 @@ export function firstline(source: string): string {
32
32
  }
33
33
  }
34
34
 
35
- export function isEmpty(line: string): boolean {
35
+ export function isBlank(line: string): boolean {
36
36
  return line === ''
37
37
  || line === '\n'
38
38
  || line.trimStart() === '';
@@ -1,5 +1,5 @@
1
1
  import { Parser, Ctx } from '../../data/parser';
2
- import { firstline, isEmpty } from '../constraint/line';
2
+ import { firstline, isBlank } from '../constraint/line';
3
3
  import { unshift } from 'spica/array';
4
4
 
5
5
  export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: RegExp, limit: number, separation = true): Parser<string, C, D> {
@@ -13,20 +13,20 @@ export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: Reg
13
13
  if (matches[0].indexOf(delim, delim.length) !== -1) return;
14
14
  let rest = source.slice(matches[0].length);
15
15
  // Prevent annoying parsing in editing.
16
- if (isEmpty(firstline(rest)) && firstline(rest.slice(firstline(rest).length)).trimEnd() !== delim) return;
16
+ if (isBlank(firstline(rest)) && firstline(rest.slice(firstline(rest).length)).trimEnd() !== delim) return;
17
17
  let block = '';
18
18
  let closer = '';
19
19
  let overflow = '';
20
20
  for (let count = 1; ; ++count) {
21
21
  if (rest === '') break;
22
22
  const line = firstline(rest);
23
- if ((closer || count > limit + 1) && isEmpty(line)) break;
23
+ if ((closer || count > limit + 1) && isBlank(line)) break;
24
24
  if(closer) {
25
25
  overflow += line;
26
26
  }
27
27
  if (!closer && count <= limit + 1 && line.slice(0, delim.length) === delim && line.trimEnd() === delim) {
28
28
  closer = line;
29
- if (isEmpty(firstline(rest.slice(line.length)))) {
29
+ if (isBlank(firstline(rest.slice(line.length)))) {
30
30
  rest = rest.slice(line.length);
31
31
  break;
32
32
  }
@@ -26,7 +26,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
26
26
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
27
27
  memo: new Memo({ targets: State.backtrackers }),
28
28
  };
29
- if (context.id?.match(/[^0-9a-z-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
29
+ if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
30
30
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
31
31
  assert(!settings.id);
32
32
  type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
@@ -32,7 +32,7 @@ export function parse(source: string, opts: Options = {}, context?: MarkdownPars
32
32
  },
33
33
  memo: new Memo({ targets: State.backtrackers }),
34
34
  };
35
- if (context.id?.match(/[^0-9a-z-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
35
+ if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
36
36
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
37
37
  const node = frag();
38
38
  let index = 0;
@@ -1,28 +1,21 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
- import { union, lazy } from '../combinator';
2
+ import { union, tails, subsequence, some, line, focus, lazy } from '../combinator';
3
+ import { link } from './inline/link';
3
4
  import { autolink as autolink_ } from './inline/autolink';
4
- import { linebreak, unescsource } from './source';
5
+ import { linebreak, unescsource, str } from './source';
6
+ import { format } from './util';
5
7
 
6
8
  export import AutolinkParser = MarkdownParser.AutolinkParser;
7
9
 
8
- const delimiter = /[@#>0-9A-Za-z\n]|\S[#>]/;
10
+ export const autolink: AutolinkParser = lazy(() => some(line(subsequence([
11
+ lineurl,
12
+ some(union([
13
+ autolink_,
14
+ linebreak,
15
+ unescsource,
16
+ ])),
17
+ ]))));
9
18
 
10
- export const autolink: AutolinkParser = ({ source, context }) => {
11
- if (source === '') return;
12
- assert(source[0] !== '\x1B');
13
- const i = source.search(delimiter);
14
- switch (i) {
15
- case -1:
16
- return [[source], ''];
17
- case 0:
18
- return parser({ source, context });
19
- default:
20
- return [[source.slice(0, i)], source.slice(i)];
21
- }
22
- };
23
-
24
- const parser: AutolinkParser = lazy(() => union([
25
- autolink_,
26
- linebreak,
27
- unescsource
28
- ]));
19
+ export const lineurl: AutolinkParser.LineUrlParser = lazy(() => focus(
20
+ /^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
21
+ format(tails([str('!'), link]))));
@@ -25,7 +25,7 @@ const source: BlockquoteParser.SourceParser = lazy(() => fmap(
25
25
  convert(unindent, source)),
26
26
  rewrite(
27
27
  some(contentline, opener),
28
- convert(unindent, fmap(some(autolink), ns => [html('pre', defrag(ns))]))),
28
+ convert(unindent, fmap(autolink, ns => [html('pre', defrag(ns))]))),
29
29
  ]))),
30
30
  ns => [html('blockquote', ns)]));
31
31
 
@@ -1,6 +1,6 @@
1
1
  import { CodeBlockParser } from '../block';
2
2
  import { eval } from '../../combinator/data/parser';
3
- import { some, block, validate, fence, clear, fmap } from '../../combinator';
3
+ import { block, validate, fence, clear, fmap } from '../../combinator';
4
4
  import { autolink } from '../autolink';
5
5
  import { html, defrag } from 'typed-dom/dom';
6
6
 
@@ -69,6 +69,6 @@ export const codeblock: CodeBlockParser = block(validate('```', fmap(
69
69
  params.lang
70
70
  ? context.caches?.code?.get(`${params.lang ?? ''}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes ||
71
71
  body.slice(0, -1) || undefined
72
- : defrag(eval(some(autolink)({ source: body.slice(0, -1), context }), [])));
72
+ : defrag(eval(autolink({ source: body.slice(0, -1), context }), [])));
73
73
  return [el];
74
74
  })));
@@ -37,8 +37,8 @@ describe('Unit: parser/block/olist', () => {
37
37
  // pending
38
38
  assert.deepStrictEqual(inspect(parser('1. ')), [['<ol><li></li></ol>'], '']);
39
39
  // filled
40
- assert.deepStrictEqual(inspect(parser('1. \\')), [['<ol><li></li></ol>'], '']);
41
- assert.deepStrictEqual(inspect(parser('1. \\\n')), [['<ol><li></li></ol>'], '']);
40
+ assert.deepStrictEqual(inspect(parser('1. \\')), [['<ol><li id="index::\\">\\</li></ol>'], '']);
41
+ assert.deepStrictEqual(inspect(parser('1. \\\n')), [['<ol><li id="index::\\">\\</li></ol>'], '']);
42
42
  assert.deepStrictEqual(inspect(parser('1. -')), [['<ol><li id="index::-">-</li></ol>'], '']);
43
43
  assert.deepStrictEqual(inspect(parser('1. -\n')), [['<ol><li id="index::-">-</li></ol>'], '']);
44
44
  // pending
@@ -6,7 +6,7 @@ import { ilist_ } from './ilist';
6
6
  import { inline, indexee, indexer } from '../inline';
7
7
  import { contentline } from '../source';
8
8
  import { State } from '../context';
9
- import { trimBlank } from '../visibility';
9
+ import { visualize, trimBlank } from '../visibility';
10
10
  import { memoize } from 'spica/memoize';
11
11
  import { shift } from 'spica/array';
12
12
  import { html, define, defrag } from 'typed-dom/dom';
@@ -37,7 +37,7 @@ const list = (type: string, form: string): OListParser.ListParser => fmap(
37
37
  some(creation(1, false, union([
38
38
  indexee(fmap(fallback(
39
39
  inits([
40
- line(open(heads[form], subsequence([checkbox, trimBlank(some(union([indexer, inline])))]), true)),
40
+ line(open(heads[form], subsequence([checkbox, trimBlank(visualize(some(union([indexer, inline]))))]), true)),
41
41
  indent(union([ulist_, olist_, ilist_])),
42
42
  ]),
43
43
  invalid),
@@ -30,6 +30,9 @@ 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>'], '']);
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>'], '']);
33
36
  assert.deepStrictEqual(inspect(parser('\ta')), [['<p>\ta</p>'], '']);
34
37
  });
35
38
 
@@ -14,8 +14,7 @@ export const cite: ReplyParser.CiteParser = creation(1, false, line(fmap(validat
14
14
  // リンクの実装は後で検討
15
15
  focus(/^>>\.(?=\s*$)/, () => [[html('a', { class: 'anchor' }, '>>.')], '']),
16
16
  focus(/^>>#\S*(?=\s*$)/, ({ source }) => [[html('a', { class: 'anchor' }, source)], '']),
17
- // Support all domains, but don't support IP(v6) addresses.
18
- focus(/^>>https?:\/\/[^\p{C}\p{S}\p{P}\s]\S*(?=\s*$)/u, ({ source }) => [[html('a', { class: 'anchor', href: source.slice(2).trimEnd(), target: '_blank' }, source)], '']),
17
+ focus(/^>>https?:\/\/(?:[[]|[^\p{C}\p{S}\p{P}\s])\S*(?=\s*$)/u, ({ source }) => [[html('a', { class: 'anchor', href: source.slice(2).trimEnd(), target: '_blank' }, source)], '']),
19
18
  ]),
20
19
  ]))),
21
20
  ([el, quotes = '']: [HTMLElement, string?]) => [
@@ -55,6 +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>'], '']);
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>'], '']);
58
61
  });
59
62
 
60
63
  });
@@ -1,9 +1,10 @@
1
1
  import { ReplyParser } from '../../block';
2
2
  import { eval } from '../../../combinator/data/parser';
3
- import { union, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
3
+ import { union, subsequence, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
4
4
  import { math } from '../../inline/math';
5
- import { str, anyline } from '../../source';
6
- import { autolink } from '../../autolink';
5
+ import { autolink } from '../../inline/autolink';
6
+ import { linebreak, unescsource, str, anyline } from '../../source';
7
+ import { lineurl } from '../../autolink';
7
8
  import { html, defrag } from 'typed-dom/dom';
8
9
 
9
10
  export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
@@ -40,8 +41,8 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
40
41
  const quotes = source.match(/^>+[^\S\n]/mg)!;
41
42
  assert(quotes);
42
43
  assert(quotes.length > 0);
43
- const content = lines.reduce((acc, line, row) => acc + line.slice(quotes[row].length), '');
44
- const nodes = eval(some(text)({ source: content, context }), []);
44
+ const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
45
+ const nodes = eval(text({ source: content, context }), []);
45
46
  nodes.unshift(quotes.shift()!);
46
47
  for (let i = 0; i < nodes.length; ++i) {
47
48
  const child = nodes[i] as string | Text | Element;
@@ -71,7 +72,12 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
71
72
  return [nodes, ''];
72
73
  };
73
74
 
74
- const text: ReplyParser.QuoteParser.TextParser = union([
75
- math,
76
- autolink,
77
- ]);
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
+ ])));
@@ -26,6 +26,6 @@ const source: SidefenceParser.SourceParser = lazy(() => fmap(
26
26
  convert(unindent, source)),
27
27
  rewrite(
28
28
  some(contentline, opener),
29
- convert(unindent, fmap(some(autolink), ns => [html('pre', defrag(ns))]))),
29
+ convert(unindent, fmap(autolink, ns => [html('pre', defrag(ns))]))),
30
30
  ]))),
31
31
  ns => [html('blockquote', ns)]));
@@ -26,8 +26,8 @@ describe('Unit: parser/block/ulist', () => {
26
26
  // pending
27
27
  assert.deepStrictEqual(inspect(parser('- ')), [['<ul><li></li></ul>'], '']);
28
28
  // filled
29
- assert.deepStrictEqual(inspect(parser('- \\')), [['<ul><li></li></ul>'], '']);
30
- assert.deepStrictEqual(inspect(parser('- \\\n')), [['<ul><li></li></ul>'], '']);
29
+ assert.deepStrictEqual(inspect(parser('- \\')), [['<ul><li id="index::\\">\\</li></ul>'], '']);
30
+ assert.deepStrictEqual(inspect(parser('- \\\n')), [['<ul><li id="index::\\">\\</li></ul>'], '']);
31
31
  assert.deepStrictEqual(inspect(parser('- -')), [['<ul><li id="index::-">-</li></ul>'], '']);
32
32
  assert.deepStrictEqual(inspect(parser('- -\n')), [['<ul><li id="index::-">-</li></ul>'], '']);
33
33
  });
@@ -4,7 +4,7 @@ import { olist_, invalid } from './olist';
4
4
  import { ilist_ } from './ilist';
5
5
  import { inline, indexer, indexee } from '../inline';
6
6
  import { State } from '../context';
7
- import { trimBlank } from '../visibility';
7
+ import { visualize, trimBlank } from '../visibility';
8
8
  import { unshift } from 'spica/array';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
@@ -18,7 +18,7 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
18
18
  some(creation(1, false, union([
19
19
  indexee(fmap(fallback(
20
20
  inits([
21
- line(open(/^-(?:$|\s)/, subsequence([checkbox, trimBlank(some(union([indexer, inline])))]), true)),
21
+ line(open(/^-(?:$|\s)/, subsequence([checkbox, trimBlank(visualize(some(union([indexer, inline]))))]), true)),
22
22
  indent(union([ulist_, olist_, ilist_])),
23
23
  ]),
24
24
  invalid),
@@ -14,7 +14,7 @@ export const index: IndexParser = lazy(() => validate('[#', fmap(indexee(surroun
14
14
  constraint(State.index, false,
15
15
  syntax(Syntax.index, 2, 1, State.linkers | State.media,
16
16
  startTight(
17
- open(stropt(/^\|?/), trimBlankEnd(some(union([
17
+ open(stropt('|'), trimBlankEnd(some(union([
18
18
  signature,
19
19
  inline,
20
20
  ]), ']', [[/^\\?\n/, 9], [']', 2]])), true)))),
@@ -9,7 +9,7 @@ export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>, opt
9
9
  }
10
10
 
11
11
  export function identity(id: string | undefined, text: string, name: 'index' | 'mark' = 'index'): string | undefined {
12
- assert(!id?.match(/[^0-9a-z-]/i));
12
+ assert(!id?.match(/[^0-9a-z/-]/i));
13
13
  assert(!text.includes('\n'));
14
14
  if (id === '') return undefined;
15
15
  text &&= text.trim().replace(/\s+/g, '_');
@@ -1,6 +1,6 @@
1
1
  import { AnyLineParser, EmptyLineParser, ContentLineParser } from '../source';
2
- import { line, isEmpty } from '../../combinator';
2
+ import { line, isBlank } from '../../combinator';
3
3
 
4
4
  export const anyline: AnyLineParser = line(() => [[], '']);
5
- export const emptyline: EmptyLineParser = line(i => isEmpty(i.source) ? [[], ''] : undefined);
6
- export const contentline: ContentLineParser = line(i => !isEmpty(i.source) ? [[], ''] : undefined);
5
+ export const emptyline: EmptyLineParser = line(i => isBlank(i.source) ? [[], ''] : undefined);
6
+ export const contentline: ContentLineParser = line(i => !isBlank(i.source) ? [[], ''] : undefined);
@@ -31,7 +31,7 @@ export function stropt(pattern: string | RegExp): Parser<string, Context<StrPars
31
31
  if (source === '') return;
32
32
  return source.slice(0, pattern.length) === pattern
33
33
  ? [[pattern], source.slice(pattern.length)]
34
- : undefined;
34
+ : [[''], source];
35
35
  })
36
36
  : creation(1, false, ({ source }) => {
37
37
  if (source === '') return;
@@ -1,3 +1,13 @@
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
+
1
11
  export function stringify(nodes: readonly (HTMLElement | string)[]): string {
2
12
  let acc = '';
3
13
  for (let i = 0; i < nodes.length; ++i) {
@@ -4,6 +4,7 @@ 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';
7
8
  import { invisibleHTMLEntityNames } from './api/normalize';
8
9
  import { reduce } from 'spica/memoize';
9
10
  import { push } from 'spica/array';
@@ -16,7 +17,7 @@ export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Pa
16
17
  return union([
17
18
  convert(
18
19
  source => source.replace(blankline, line => line.replace(/[\\&<]/g, '\x1B$&')),
19
- verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
20
+ verify(format(parser), (ns, rest, context) => !rest && hasVisible(ns, context))),
20
21
  some(union([linebreak, unescsource])),
21
22
  ]);
22
23
  }
package/src/util/quote.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { exec } from '../combinator/data/parser';
2
2
  import { cite } from '../parser/block/reply/cite';
3
- import { define } from 'typed-dom/dom';
3
+ //import { url } from '../parser/inline/autolink/url';
4
4
 
5
5
  export function quote(anchor: string, range: Range): string {
6
6
  if (exec(cite({ source: `>>${anchor}`, context: {} })) !== '') throw new Error(`Invalid anchor: ${anchor}`);
@@ -13,8 +13,15 @@ export function quote(anchor: string, range: Range): string {
13
13
  switch (true) {
14
14
  case el.matches('code'):
15
15
  case el.matches('.math'):
16
- define(el, el.getAttribute('data-src')!);
16
+ el.replaceWith(el.getAttribute('data-src')!);
17
17
  continue;
18
+ //case el.matches('.url'):
19
+ // if (exec(url({ source: el.getAttribute('href')!, context: {} })) === '') continue;
20
+ // el.replaceWith(
21
+ // /[\s{}]/.test(el.getAttribute('href')!)
22
+ // ? `{ ${el.getAttribute('href')} }`
23
+ // : `{${el.getAttribute('href')}}`);
24
+ // continue;
18
25
  case el.matches('.media'):
19
26
  el.replaceWith(
20
27
  /[\s{}]/.test(el.getAttribute('data-src')!)