securemark 0.255.1 → 0.256.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.256.0
4
+
5
+ - Decrease the buget size to 50,000.
6
+
3
7
  ## 0.255.1
4
8
 
5
9
  - Refactoring.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.255.1 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.256.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("DOMPurify"), require("Prism"));
@@ -2009,22 +2009,13 @@ const alias_1 = __webpack_require__(5406);
2009
2009
 
2010
2010
  const parser_1 = __webpack_require__(6728);
2011
2011
 
2012
- function validate(patterns, has, end, parser) {
2013
- if (typeof has === 'function') return validate(patterns, '', '', has);
2014
- if (typeof end === 'function') return validate(patterns, has, '', end);
2015
- if (!(0, alias_1.isArray)(patterns)) return validate([patterns], has, end, parser);
2012
+ function validate(patterns, has, parser) {
2013
+ if (typeof has === 'function') return validate(patterns, '', has);
2014
+ if (!(0, alias_1.isArray)(patterns)) return validate([patterns], has, parser);
2016
2015
  const match = (0, global_1.Function)(['"use strict";', 'return source =>', '0', ...patterns.map(pattern => typeof pattern === 'string' ? `|| source.slice(0, ${pattern.length}) === '${pattern}'` : `|| /${pattern.source}/${pattern.flags}.test(source)`)].join(''))();
2017
-
2018
- const match2 = source => {
2019
- if (!has) return true;
2020
- const i = end ? source.indexOf(end, 1) : -1;
2021
- return i !== -1 ? source.slice(0, i).indexOf(has, 1) !== -1 : source.indexOf(has, 1) !== -1;
2022
- };
2023
-
2024
2016
  return (source, context) => {
2025
2017
  if (source === '') return;
2026
2018
  if (!match(source)) return;
2027
- if (!match2(source)) return;
2028
2019
  const result = parser(source, context);
2029
2020
  if (!result) return;
2030
2021
  return (0, parser_1.exec)(result).length < source.length ? result : global_1.undefined;
@@ -3645,7 +3636,7 @@ const random_1 = __webpack_require__(7325);
3645
3636
 
3646
3637
  exports.block = (0, combinator_1.creator)(error((0, combinator_1.reset)({
3647
3638
  resources: {
3648
- budget: 100 * 1000,
3639
+ budget: 50 * 1000,
3649
3640
  recursion: 200
3650
3641
  }
3651
3642
  }, (0, combinator_1.union)([source_1.emptyline, horizontalrule_1.horizontalrule, heading_1.heading, ulist_1.ulist, olist_1.olist, ilist_1.ilist, dlist_1.dlist, table_1.table, codeblock_1.codeblock, mathblock_1.mathblock, extension_1.extension, sidefence_1.sidefence, blockquote_1.blockquote, reply_1.reply, paragraph_1.paragraph]))));
@@ -5383,7 +5374,7 @@ const util_1 = __webpack_require__(9437);
5383
5374
 
5384
5375
  const dom_1 = __webpack_require__(3252);
5385
5376
 
5386
- exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('((', '))', '\n', (0, combinator_1.fmap)((0, combinator_1.surround)('((', (0, combinator_1.guard)(context => context.syntax?.inline?.annotation ?? true, (0, combinator_1.context)({
5377
+ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('((', (0, combinator_1.fmap)((0, combinator_1.surround)('((', (0, combinator_1.guard)(context => context.syntax?.inline?.annotation ?? true, (0, combinator_1.context)({
5387
5378
  syntax: {
5388
5379
  inline: {
5389
5380
  annotation: false,
@@ -5398,9 +5389,9 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0,
5398
5389
  }
5399
5390
  },
5400
5391
  delimiters: global_1.undefined
5401
- }, (0, util_1.trimBlank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', /^\\?\n/)))), '))'), ns => [(0, dom_1.html)('sup', {
5392
+ }, (0, util_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', /^\\?\n/)))), '))'), ns => [(0, dom_1.html)('sup', {
5402
5393
  class: 'annotation'
5403
- }, [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])]))));
5394
+ }, [(0, dom_1.html)('span', (0, util_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])]))));
5404
5395
 
5405
5396
  /***/ }),
5406
5397
 
@@ -5695,7 +5686,7 @@ const dom_1 = __webpack_require__(3252);
5695
5686
  const array_1 = __webpack_require__(8112);
5696
5687
 
5697
5688
  const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
5698
- exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, source_1.str)(index), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)(inline_1.inline, ')'), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5689
+ exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(0, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, source_1.str)(index), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)(inline_1.inline, ')'), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5699
5690
  class: 'paren'
5700
5691
  }, (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)(as, bs), cs)))], rest], ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('('), (0, source_1.str)(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)(inline_1.inline, ')'), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5701
5692
  class: 'paren'
@@ -5948,7 +5939,7 @@ const util_1 = __webpack_require__(9437);
5948
5939
 
5949
5940
  const dom_1 = __webpack_require__(3252);
5950
5941
 
5951
- exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[#', ']', '\n', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.fmap)((0, combinator_1.surround)('[#', (0, combinator_1.guard)(context => context.syntax?.inline?.index ?? true, (0, util_1.startTight)((0, combinator_1.context)({
5942
+ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[#', (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.fmap)((0, combinator_1.surround)('[#', (0, combinator_1.guard)(context => context.syntax?.inline?.index ?? true, (0, util_1.startTight)((0, combinator_1.context)({
5952
5943
  syntax: {
5953
5944
  inline: {
5954
5945
  annotation: false,
@@ -6165,7 +6156,7 @@ const array_1 = __webpack_require__(8112); // Don't use the symbols already used
6165
6156
  // All syntax surrounded by square brackets shouldn't contain line breaks.
6166
6157
 
6167
6158
 
6168
- exports.placeholder = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)(['[:', '[^'], ']', '\n', (0, combinator_1.surround)((0, source_1.str)(/^\[[:^]/), (0, util_1.startTight)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']')), (0, source_1.str)(']'), false, ([as, bs], rest) => [[(0, dom_1.html)('span', {
6159
+ exports.placeholder = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)(['[:', '[^'], (0, combinator_1.surround)((0, source_1.str)(/^\[[:^]/), (0, util_1.startTight)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', /^\\?\n/)), (0, source_1.str)(']'), false, ([as, bs], rest) => [[(0, dom_1.html)('span', {
6169
6160
  class: 'invalid',
6170
6161
  'data-invalid-syntax': 'extension',
6171
6162
  'data-invalid-type': 'syntax',
@@ -6365,7 +6356,7 @@ const optspec = {
6365
6356
  rel: ['nofollow']
6366
6357
  };
6367
6358
  Object.setPrototypeOf(optspec, null);
6368
- exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['[', '{'], '}', '\n', (0, combinator_1.bind)((0, combinator_1.guard)(context => context.syntax?.inline?.link ?? true, (0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.context)({
6359
+ exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['[', '{'], (0, combinator_1.bind)((0, combinator_1.guard)(context => context.syntax?.inline?.link ?? true, (0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.context)({
6369
6360
  syntax: {
6370
6361
  inline: {
6371
6362
  link: false
@@ -6384,7 +6375,8 @@ exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, co
6384
6375
  autolink: false
6385
6376
  }
6386
6377
  }
6387
- }, (0, util_1.trimBlank)((0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/))), ']', 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) => {
6378
+ }, (0, util_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/))), ']', 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) => {
6379
+ content = (0, util_1.trimNodeEnd)(content);
6388
6380
  if ((0, parser_1.eval)((0, combinator_1.some)(autolink_1.autolink)((0, util_1.stringify)(content), context))?.some(node => typeof node === 'object')) return;
6389
6381
  const INSECURE_URI = params.shift();
6390
6382
  const el = elem(INSECURE_URI, (0, dom_1.defrag)(content), new url_1.ReadonlyURL(resolve(INSECURE_URI, context.host ?? global_1.location, context.url ?? context.host ?? global_1.location), context.host?.href || global_1.location.href), context.host?.origin || global_1.location.origin);
@@ -6572,7 +6564,7 @@ const optspec = {
6572
6564
  rel: global_1.undefined
6573
6565
  };
6574
6566
  Object.setPrototypeOf(optspec, null);
6575
- exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['![', '!{'], '}', '\n', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.guard)(context => context.syntax?.inline?.media ?? true, (0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)(/^\[(?!\s*\\\s)/, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', /^\\?\n/), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))]))), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6567
+ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.creator)(10, (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.open)('!', (0, combinator_1.guard)(context => context.syntax?.inline?.media ?? true, (0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)(/^\[(?!\s*\\\s)/, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', /^\\?\n/), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))]))), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6576
6568
  const INSECURE_URI = params.shift();
6577
6569
  const url = new url_1.ReadonlyURL((0, link_1.resolve)(INSECURE_URI, context.host ?? global_1.location, context.url ?? context.host ?? global_1.location), context.host?.href || global_1.location.href);
6578
6570
  let cache;
@@ -6663,7 +6655,7 @@ const util_1 = __webpack_require__(9437);
6663
6655
 
6664
6656
  const dom_1 = __webpack_require__(3252);
6665
6657
 
6666
- exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[[', ']]', '\n', (0, combinator_1.fmap)((0, combinator_1.surround)('[[', (0, combinator_1.guard)(context => context.syntax?.inline?.reference ?? true, (0, combinator_1.context)({
6658
+ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[[', (0, combinator_1.fmap)((0, combinator_1.surround)('[[', (0, combinator_1.guard)(context => context.syntax?.inline?.reference ?? true, (0, combinator_1.context)({
6667
6659
  syntax: {
6668
6660
  inline: {
6669
6661
  annotation: false,
@@ -6677,7 +6669,7 @@ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, c
6677
6669
  }
6678
6670
  },
6679
6671
  delimiters: global_1.undefined
6680
- }, (0, combinator_1.subsequence)([abbr, (0, combinator_1.open)((0, source_1.stropt)(/^(?=\^)/), (0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/)), (0, util_1.trimBlank)((0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/))]))), ']]'), ns => [(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])]))));
6672
+ }, (0, combinator_1.subsequence)([abbr, (0, combinator_1.open)((0, source_1.stropt)(/^(?=\^)/), (0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/)), (0, util_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', /^\\?\n/))]))), ']]'), ns => [(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, util_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])]))));
6681
6673
  const abbr = (0, combinator_1.creator)((0, combinator_1.bind)((0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]), /^\|?(?=]])|^\|[^\S\n]*/), ([source], rest) => [[(0, dom_1.html)('abbr', source)], rest.replace(util_1.regBlankStart, '')]));
6682
6674
 
6683
6675
  function attributes(ns) {
@@ -6723,7 +6715,7 @@ const dom_1 = __webpack_require__(3252);
6723
6715
 
6724
6716
  const array_1 = __webpack_require__(8112);
6725
6717
 
6726
- exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[', ')', '\n', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.sequence)([(0, combinator_1.surround)('[', (0, combinator_1.focus)(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'), (0, combinator_1.surround)('(', (0, combinator_1.focus)(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')')]), ([texts]) => (0, util_1.isStartTightNodes)(texts)), ([texts, rubies], rest) => {
6718
+ exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.creator)((0, combinator_1.validate)('[', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.sequence)([(0, combinator_1.surround)('[', (0, combinator_1.focus)(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'), (0, combinator_1.surround)('(', (0, combinator_1.focus)(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')')]), ([texts]) => (0, util_1.isStartTightNodes)(texts)), ([texts, rubies], rest) => {
6727
6719
  const tail = typeof texts[texts.length - 1] === 'object' ? [texts.pop()] : [];
6728
6720
  tail.length === 0 && texts[texts.length - 1] === '' && texts.pop();
6729
6721
 
@@ -7769,7 +7761,7 @@ exports.unescsource = (0, combinator_1.creator)(source => {
7769
7761
  Object.defineProperty(exports, "__esModule", ({
7770
7762
  value: true
7771
7763
  }));
7772
- exports.stringify = exports.trimBlankEnd = exports.trimBlankStart = exports.trimBlank = exports.isStartTightNodes = exports.isStartLooseNodes = exports.startTight = exports.startLoose = exports.visualize = exports.blankWith = exports.regBlankStart = void 0;
7764
+ exports.stringify = exports.trimNodeEnd = exports.trimBlankEnd = exports.trimBlankStart = exports.trimBlank = exports.isStartTightNodes = exports.isStartLooseNodes = exports.startTight = exports.startLoose = exports.visualize = exports.blankWith = exports.regBlankStart = void 0;
7773
7765
 
7774
7766
  const global_1 = __webpack_require__(4128);
7775
7767
 
@@ -7986,6 +7978,8 @@ function trimNodeEnd(nodes) {
7986
7978
  return (0, array_1.push)(nodes, skip);
7987
7979
  }
7988
7980
 
7981
+ exports.trimNodeEnd = trimNodeEnd;
7982
+
7989
7983
  function stringify(nodes) {
7990
7984
  let acc = '';
7991
7985
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.255.1",
3
+ "version": "0.256.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",
@@ -9,11 +9,9 @@ import { Parser, Ctx, Tree, Context, eval, exec, check } from '../../data/parser
9
9
 
10
10
  export function validate<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P): P;
11
11
  export function validate<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], has: string, parser: P): P;
12
- export function validate<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], has: string, end: string, parser: P): P;
13
- export function validate<T>(patterns: string | RegExp | (string | RegExp)[], has: string | Parser<T>, end?: string | Parser<T>, parser?: Parser<T>): Parser<T> {
14
- if (typeof has === 'function') return validate(patterns, '', '', has);
15
- if (typeof end === 'function') return validate(patterns, has, '', end);
16
- if (!isArray(patterns)) return validate([patterns], has, end!, parser!);
12
+ export function validate<T>(patterns: string | RegExp | (string | RegExp)[], has: string | Parser<T>, parser?: Parser<T>): Parser<T> {
13
+ if (typeof has === 'function') return validate(patterns, '', has);
14
+ if (!isArray(patterns)) return validate([patterns], has, parser!);
17
15
  assert(patterns.length > 0);
18
16
  assert(patterns.every(pattern => pattern instanceof RegExp ? !pattern.flags.match(/[gmy]/) && pattern.source.startsWith('^') : true));
19
17
  assert(parser);
@@ -26,17 +24,9 @@ export function validate<T>(patterns: string | RegExp | (string | RegExp)[], has
26
24
  ? `|| source.slice(0, ${pattern.length}) === '${pattern}'`
27
25
  : `|| /${pattern.source}/${pattern.flags}.test(source)`),
28
26
  ].join(''))();
29
- const match2 = (source: string): boolean => {
30
- if (!has) return true;
31
- const i = end ? source.indexOf(end, 1) : -1;
32
- return i !== -1
33
- ? source.slice(0, i).indexOf(has, 1) !== -1
34
- : source.indexOf(has, 1) !== -1;
35
- };
36
27
  return (source, context) => {
37
28
  if (source === '') return;
38
29
  if (!match(source)) return;
39
- if (!match2(source)) return;
40
30
  const result = parser!(source, context);
41
31
  assert(check(source, result));
42
32
  if (!result) return;
@@ -4,7 +4,7 @@ export function creator<P extends Parser<unknown>>(parser: P): P;
4
4
  export function creator<P extends Parser<unknown>>(cost: number, parser: P): P;
5
5
  export function creator(cost: number | Parser<unknown>, parser?: Parser<unknown>): Parser<unknown> {
6
6
  if (typeof cost === 'function') return creator(1, cost);
7
- assert(cost > 0);
7
+ assert(cost >= 0);
8
8
  return (source, context) => {
9
9
  const { resources = { budget: 1, recursion: 1 } } = context;
10
10
  if (resources.budget <= 0) throw new Error('Too many creations.');
@@ -229,10 +229,15 @@ describe('Unit: parser/api/parse', () => {
229
229
  [`<p>${'"[% '.repeat(100).trim()}</p>`]);
230
230
  });
231
231
 
232
+ if (!navigator.userAgent.includes('Chrome')) return;
233
+
232
234
  it('recursion', () => {
233
235
  assert.deepStrictEqual(
234
236
  [...parse('('.repeat(199)).children].map(el => el.outerHTML),
235
237
  [`<p>${'('.repeat(199)}</p>`]);
238
+ });
239
+
240
+ it('recursion error', () => {
236
241
  assert.deepStrictEqual(
237
242
  [...parse('('.repeat(200) + '\n\na').children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
238
243
  [
@@ -36,7 +36,7 @@ export import ReplyParser = BlockParser.ReplyParser;
36
36
  export import ParagraphParser = BlockParser.ParagraphParser;
37
37
 
38
38
  export const block: BlockParser = creator(error(
39
- reset({ resources: { budget: 100 * 1000, recursion: 200 } },
39
+ reset({ resources: { budget: 50 * 1000, recursion: 200 } },
40
40
  union([
41
41
  emptyline,
42
42
  horizontalrule,
@@ -2,10 +2,10 @@ import { undefined } from 'spica/global';
2
2
  import { AnnotationParser } from '../inline';
3
3
  import { union, some, validate, guard, context, creator, surround, lazy, fmap } from '../../combinator';
4
4
  import { inline } from '../inline';
5
- import { trimBlank } from '../util';
5
+ import { trimBlankStart, trimNodeEnd } from '../util';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
 
8
- export const annotation: AnnotationParser = lazy(() => creator(validate('((', '))', '\n', fmap(surround(
8
+ export const annotation: AnnotationParser = lazy(() => creator(validate('((', fmap(surround(
9
9
  '((',
10
10
  guard(context => context.syntax?.inline?.annotation ?? true,
11
11
  context({ syntax: { inline: {
@@ -19,6 +19,6 @@ export const annotation: AnnotationParser = lazy(() => creator(validate('((', ')
19
19
  //link: true,
20
20
  //autolink: true,
21
21
  }}, delimiters: undefined },
22
- trimBlank(some(union([inline]), ')', /^\\?\n/)))),
22
+ trimBlankStart(some(union([inline]), ')', /^\\?\n/)))),
23
23
  '))'),
24
- ns => [html('sup', { class: 'annotation' }, [html('span', defrag(ns))])]))));
24
+ ns => [html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])]))));
@@ -8,7 +8,7 @@ import { unshift, push } from 'spica/array';
8
8
 
9
9
  const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
10
10
 
11
- export const bracket: BracketParser = lazy(() => creator(union([
11
+ export const bracket: BracketParser = lazy(() => creator(0, union([
12
12
  surround(str('('), str(index), str(')')),
13
13
  surround(str('('), some(inline, ')'), str(')'), true,
14
14
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
@@ -9,7 +9,7 @@ import { html, define, defrag } from 'typed-dom/dom';
9
9
 
10
10
  import IndexParser = ExtensionParser.IndexParser;
11
11
 
12
- export const index: IndexParser = lazy(() => creator(validate('[#', ']', '\n', fmap(indexee(fmap(surround(
12
+ export const index: IndexParser = lazy(() => creator(validate('[#', fmap(indexee(fmap(surround(
13
13
  '[#',
14
14
  guard(context => context.syntax?.inline?.index ?? true,
15
15
  startTight(
@@ -21,13 +21,13 @@ describe('Unit: parser/inline/extension/placeholder', () => {
21
21
  assert.deepStrictEqual(inspect(parser('[^\na]')), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('[^\\\na]')), undefined);
23
23
  assert.deepStrictEqual(inspect(parser('[^ !http://host]')), undefined);
24
- assert.deepStrictEqual(inspect(parser('[^a')), undefined);
25
- assert.deepStrictEqual(inspect(parser('[^a\n]')), undefined);
26
- assert.deepStrictEqual(inspect(parser('[^a\n\n]')), undefined);
27
- assert.deepStrictEqual(inspect(parser('[^a\\\n]')), undefined);
28
- assert.deepStrictEqual(inspect(parser('[^a\\\n\\\n]')), undefined);
29
- assert.deepStrictEqual(inspect(parser('[^a\nb]')), undefined);
30
- assert.deepStrictEqual(inspect(parser('[^a\\\nb]')), undefined);
24
+ assert.deepStrictEqual(inspect(parser('[^a')), [['[^', 'a'], '']);
25
+ assert.deepStrictEqual(inspect(parser('[^a\n]')), [['[^', 'a'], '\n]']);
26
+ assert.deepStrictEqual(inspect(parser('[^a\n\n]')), [['[^', 'a'], '\n\n]']);
27
+ assert.deepStrictEqual(inspect(parser('[^a\\\n]')), [['[^', 'a'], '\\\n]']);
28
+ assert.deepStrictEqual(inspect(parser('[^a\\\n\\\n]')), [['[^', 'a'], '\\\n\\\n]']);
29
+ assert.deepStrictEqual(inspect(parser('[^a\nb]')), [['[^', 'a'], '\nb]']);
30
+ assert.deepStrictEqual(inspect(parser('[^a\\\nb]')), [['[^', 'a'], '\\\nb]']);
31
31
  assert.deepStrictEqual(inspect(parser('[[]')), undefined);
32
32
  assert.deepStrictEqual(inspect(parser('[]]')), undefined);
33
33
  assert.deepStrictEqual(inspect(parser('[[]]')), undefined);
@@ -10,9 +10,9 @@ import { unshift } from 'spica/array';
10
10
 
11
11
  // All syntax surrounded by square brackets shouldn't contain line breaks.
12
12
 
13
- export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => creator(validate(['[:', '[^'], ']', '\n', surround(
13
+ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => creator(validate(['[:', '[^'], surround(
14
14
  str(/^\[[:^]/),
15
- startTight(some(union([inline]), ']')),
15
+ startTight(some(union([inline]), ']', /^\\?\n/)),
16
16
  str(']'), false,
17
17
  ([as, bs], rest) => [[
18
18
  html('span', {
@@ -6,7 +6,7 @@ import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { autolink } from '../autolink';
8
8
  import { str } from '../source';
9
- import { trimBlank, stringify } from '../util';
9
+ import { trimBlankStart, trimNodeEnd, stringify } from '../util';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
  import { ReadonlyURL } from 'spica/url';
12
12
 
@@ -15,7 +15,7 @@ const optspec = {
15
15
  } as const;
16
16
  Object.setPrototypeOf(optspec, null);
17
17
 
18
- export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}', '\n', bind(
18
+ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], bind(
19
19
  guard(context => context.syntax?.inline?.link ?? true,
20
20
  reverse(tails([
21
21
  context({ syntax: { inline: {
@@ -36,7 +36,7 @@ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}',
36
36
  media: false,
37
37
  autolink: false,
38
38
  }}},
39
- trimBlank(some(inline, ']', /^\\?\n/))),
39
+ trimBlankStart(some(inline, ']', /^\\?\n/))),
40
40
  ']',
41
41
  true),
42
42
  ]))),
@@ -44,6 +44,7 @@ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}',
44
44
  ]))),
45
45
  ([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
46
46
  assert(params.every(p => typeof p === 'string'));
47
+ content = trimNodeEnd(content);
47
48
  if (eval(some(autolink)(stringify(content), context))?.some(node => typeof node === 'object')) return;
48
49
  assert(!html('div', content).querySelector('a, .media, .annotation, .reference') || (content[0] as HTMLElement).matches('.media'));
49
50
  const INSECURE_URI = params.shift()!;
@@ -17,7 +17,7 @@ const optspec = {
17
17
  } as const;
18
18
  Object.setPrototypeOf(optspec, null);
19
19
 
20
- export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'], '}', '\n', bind(verify(fmap(open(
20
+ export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'], bind(verify(fmap(open(
21
21
  '!',
22
22
  guard(context => context.syntax?.inline?.media ?? true,
23
23
  tails([
@@ -57,7 +57,7 @@ describe('Unit: parser/inline/reference', () => {
57
57
  assert.deepStrictEqual(inspect(parser('[[^a,]]')), [['<sup class="reference" data-abbr="a,"><span></span></sup>'], '']);
58
58
  assert.deepStrictEqual(inspect(parser('[[^a, ]]')), [['<sup class="reference" data-abbr="a,"><span></span></sup>'], '']);
59
59
  assert.deepStrictEqual(inspect(parser('[[^a ]]')), [['<sup class="reference" data-abbr="a"><span></span></sup>'], '']);
60
- assert.deepStrictEqual(inspect(parser('[[^a ]]')), [['<sup class="invalid"><span>^a </span></sup>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('[[^a ]]')), [['<sup class="invalid"><span>^a</span></sup>'], '']);
61
61
  assert.deepStrictEqual(inspect(parser('[[^a b]]')), [['<sup class="reference" data-abbr="a b"><span></span></sup>'], '']);
62
62
  assert.deepStrictEqual(inspect(parser('[[^a b]]')), [['<sup class="invalid"><span>^a b</span></sup>'], '']);
63
63
  assert.deepStrictEqual(inspect(parser('[[^a|]]')), [['<sup class="reference" data-abbr="a"><span></span></sup>'], '']);
@@ -75,7 +75,7 @@ describe('Unit: parser/inline/reference', () => {
75
75
  assert.deepStrictEqual(inspect(parser('[[^a| ]]')), [['<sup class="reference" data-abbr="a"><span></span></sup>'], '']);
76
76
  assert.deepStrictEqual(inspect(parser('[[^1]]')), [['<sup class="invalid"><span>^1</span></sup>'], '']);
77
77
  assert.deepStrictEqual(inspect(parser('[[^1a]]')), [['<sup class="reference" data-abbr="1a"><span></span></sup>'], '']);
78
- assert.deepStrictEqual(inspect(parser('[[^1 ]]')), [['<sup class="invalid"><span>^1 </span></sup>'], '']);
78
+ assert.deepStrictEqual(inspect(parser('[[^1 ]]')), [['<sup class="invalid"><span>^1</span></sup>'], '']);
79
79
  assert.deepStrictEqual(inspect(parser('[[^1 a]]')), [['<sup class="reference" data-abbr="1 a"><span></span></sup>'], '']);
80
80
  assert.deepStrictEqual(inspect(parser('[[^1|]]')), [['<sup class="invalid"><span>^1|</span></sup>'], '']);
81
81
  assert.deepStrictEqual(inspect(parser('[[^1 |]]')), [['<sup class="invalid"><span>^1 |</span></sup>'], '']);
@@ -86,11 +86,11 @@ describe('Unit: parser/inline/reference', () => {
86
86
  assert.deepStrictEqual(inspect(parser(`[[^A's, Aces']]`)), [[`<sup class="reference" data-abbr="A's, Aces'"><span></span></sup>`], '']);
87
87
  assert.deepStrictEqual(inspect(parser('[[^^]]')), [['<sup class="invalid"><span>^^</span></sup>'], '']);
88
88
  assert.deepStrictEqual(inspect(parser('[[\\^]]')), [['<sup class="reference"><span>^</span></sup>'], '']);
89
- assert.deepStrictEqual(inspect(parser('[[^ ]]')), [['<sup class="invalid"><span>^ </span></sup>'], '']);
89
+ assert.deepStrictEqual(inspect(parser('[[^ ]]')), [['<sup class="invalid"><span>^</span></sup>'], '']);
90
90
  assert.deepStrictEqual(inspect(parser('[[^ a]]')), [['<sup class="invalid"><span>^ a</span></sup>'], '']);
91
91
  assert.deepStrictEqual(inspect(parser('[[^ |]]')), [['<sup class="invalid"><span>^ |</span></sup>'], '']);
92
92
  assert.deepStrictEqual(inspect(parser('[[^ |b]]')), [['<sup class="invalid"><span>^ |b</span></sup>'], '']);
93
- assert.deepStrictEqual(inspect(parser('[[^ | ]]')), [['<sup class="invalid"><span>^ | </span></sup>'], '']);
93
+ assert.deepStrictEqual(inspect(parser('[[^ | ]]')), [['<sup class="invalid"><span>^ |</span></sup>'], '']);
94
94
  assert.deepStrictEqual(inspect(parser('[[^ | b]]')), [['<sup class="invalid"><span>^ | b</span></sup>'], '']);
95
95
  });
96
96
 
@@ -3,10 +3,10 @@ import { ReferenceParser } from '../inline';
3
3
  import { union, subsequence, some, validate, guard, context, creator, surround, open, lazy, fmap, bind } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str, stropt } from '../source';
6
- import { regBlankStart, trimBlank, stringify } from '../util';
6
+ import { regBlankStart, trimBlankStart, trimNodeEnd, stringify } from '../util';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
9
- export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
9
+ export const reference: ReferenceParser = lazy(() => creator(validate('[[', fmap(surround(
10
10
  '[[',
11
11
  guard(context => context.syntax?.inline?.reference ?? true,
12
12
  context({ syntax: { inline: {
@@ -22,10 +22,10 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
22
22
  subsequence([
23
23
  abbr,
24
24
  open(stropt(/^(?=\^)/), some(inline, ']', /^\\?\n/)),
25
- trimBlank(some(inline, ']', /^\\?\n/)),
25
+ trimBlankStart(some(inline, ']', /^\\?\n/)),
26
26
  ]))),
27
27
  ']]'),
28
- ns => [html('sup', attributes(ns), [html('span', defrag(ns))])]))));
28
+ ns => [html('sup', attributes(ns), [html('span', trimNodeEnd(defrag(ns)))])]))));
29
29
 
30
30
  const abbr: ReferenceParser.AbbrParser = creator(bind(surround(
31
31
  '^',
@@ -8,7 +8,7 @@ import { isStartTightNodes } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
  import { unshift, push } from 'spica/array';
10
10
 
11
- export const ruby: RubyParser = lazy(() => creator(validate('[', ')', '\n', bind(verify(
11
+ export const ruby: RubyParser = lazy(() => creator(validate('[', bind(verify(
12
12
  sequence([
13
13
  surround('[', focus(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'),
14
14
  surround('(', focus(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')'),
@@ -158,8 +158,8 @@ describe('Unit: parser/inline', () => {
158
158
  assert.deepStrictEqual(inspect(parser('[~http://host')), [['[', '~', '<a href="http://host" target="_blank">http://host</a>'], '']);
159
159
  assert.deepStrictEqual(inspect(parser('[~a@b')), [['[', '~', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
160
160
  assert.deepStrictEqual(inspect(parser('[~~a~~]')), [['[', '<del>a</del>', ']'], '']);
161
- assert.deepStrictEqual(inspect(parser('[^http://host')), [['[', '^', '<a href="http://host" target="_blank">http://host</a>'], '']);
162
- assert.deepStrictEqual(inspect(parser('[^a@b')), [['[', '^', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
161
+ assert.deepStrictEqual(inspect(parser('[^http://host')), [['[^', '<a href="http://host" target="_blank">http://host</a>'], '']);
162
+ assert.deepStrictEqual(inspect(parser('[^a@b')), [['[^', '<a class="email" href="mailto:a@b">a@b</a>'], '']);
163
163
  assert.deepStrictEqual(inspect(parser('[#a*b\nc*]')), [['[', '<a href="/hashtags/a" class="hashtag">#a</a>', '<em>b<br>c</em>', ']'], '']);
164
164
  assert.deepStrictEqual(inspect(parser('[*a\nb*]{/}')), [['[', '<em>a<br>b</em>', ']', '<a href="/">/</a>'], '']);
165
165
  assert.deepStrictEqual(inspect(parser('[[*a\nb*]]')), [['[', '[', '<em>a<br>b</em>', ']', ']'], '']);
@@ -183,7 +183,7 @@ export function trimBlankEnd<T extends HTMLElement | string>(parser: Parser<T>):
183
183
  // }
184
184
  // return nodes;
185
185
  //}
186
- function trimNodeEnd<T extends HTMLElement | string>(nodes: T[]): T[] {
186
+ export function trimNodeEnd<T extends HTMLElement | string>(nodes: T[]): T[] {
187
187
  const skip = nodes.length > 0 &&
188
188
  typeof nodes[nodes.length - 1] === 'object' &&
189
189
  nodes[nodes.length - 1]['className'] === 'indexer'