securemark 0.285.0 → 0.285.1

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.285.1
4
+
5
+ - Fix backtracking control.
6
+
3
7
  ## 0.285.0
4
8
 
5
9
  - Refine parsing of repeated symbols.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.285.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.285.1 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"));
@@ -996,14 +996,14 @@ function indent(opener, parser, separation = false) {
996
996
  source
997
997
  }) => [[source], '']))), ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation), (lines, rest, context) => {
998
998
  const {
999
- logger
999
+ backtracks
1000
1000
  } = context;
1001
- context.logger = {};
1001
+ context.backtracks = {};
1002
1002
  const result = parser({
1003
1003
  source: trimBlockEnd(lines.join('')),
1004
1004
  context
1005
1005
  });
1006
- context.logger = logger;
1006
+ context.backtracks = backtracks;
1007
1007
  return result && (0, parser_1.exec)(result) === '' ? [(0, parser_1.eval)(result), rest] : undefined;
1008
1008
  });
1009
1009
  }
@@ -1993,13 +1993,13 @@ const combinator_1 = __webpack_require__(3484);
1993
1993
  const link_1 = __webpack_require__(3628);
1994
1994
  const source_1 = __webpack_require__(8745);
1995
1995
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
1996
- 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.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.unescsource, closer)]))))), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink))), ({
1996
+ 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.precedence)(1, (0, combinator_1.some)((0, combinator_1.verify)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.unescsource, closer)]), ns => ns[0] !== "\u001B" /* Command.Escape */))))), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink))), ({
1997
1997
  source
1998
1998
  }) => [[source], '']]))));
1999
1999
  exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.open)(source_1.linebreak, (0, combinator_1.focus)(/^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink))), ({
2000
2000
  source
2001
2001
  }) => [[source], '']])]))));
2002
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')'), (0, source_1.str)(')'), true, undefined, undefined, 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']'), (0, source_1.str)(']'), true, undefined, undefined, 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}'), (0, source_1.str)('}'), true, undefined, undefined, 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.unescsource, '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 4 /* Backtrack.url */)])));
2002
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')'), (0, source_1.str)(')'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']'), (0, source_1.str)(']'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}'), (0, source_1.str)('}'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 4 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.unescsource, '"')), (0, source_1.str)('"'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 4 /* Backtrack.url */)])));
2003
2003
 
2004
2004
  /***/ },
2005
2005
 
@@ -3267,7 +3267,7 @@ const optspec = {
3267
3267
  rel: ['nofollow']
3268
3268
  };
3269
3269
  Object.setPrototypeOf(optspec, null);
3270
- exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(8 /* State.link */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [['\n', 9], [']', 1]])), ']', true, undefined, undefined, 1 | 8 /* Backtrack.bracket */)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/, false, undefined, undefined, 3 | 20 /* Backtrack.link */))])), ([params, content = []], rest, context) => {
3270
+ exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(8 /* State.link */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [['\n', 9], [']', 1]])), ']', true, undefined, undefined, 1 | 12 /* Backtrack.linebracket */, 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/, false, undefined, undefined, 3 | 24 /* Backtrack.link */))])), ([params, content = []], rest, context) => {
3271
3271
  if (content.length !== 0 && (0, visibility_1.trimBlankNodeEnd)(content).length === 0) return;
3272
3272
  return [[parse((0, dom_1.defrag)(content), params, context)], rest];
3273
3273
  }))))));
@@ -4343,7 +4343,7 @@ const visibility_1 = __webpack_require__(6364);
4343
4343
  const dom_1 = __webpack_require__(394);
4344
4344
  exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('((', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 4 /* State.media */, (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [['\n', 9], [')', 1]])))), '))', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', {
4345
4345
  class: 'annotation'
4346
- }, [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, 1 | 8 /* Backtrack.bracket */))));
4346
+ }, [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, 1 | 12 /* Backtrack.linebracket */, 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */))));
4347
4347
 
4348
4348
  /***/ },
4349
4349
 
@@ -5009,12 +5009,11 @@ Object.defineProperty(exports, "__esModule", ({
5009
5009
  exports.template = void 0;
5010
5010
  const combinator_1 = __webpack_require__(3484);
5011
5011
  const source_1 = __webpack_require__(8745);
5012
- const array_1 = __webpack_require__(6876);
5013
5012
  const dom_1 = __webpack_require__(394);
5014
- exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('{{', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}')), '}}', true, ([, ns = []], rest) => [[(0, dom_1.html)('span', {
5013
+ exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('{{', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.verify)((0, combinator_1.union)([bracket, source_1.escsource]), ns => ns[0] !== "\u001B" /* Command.Escape */), '}')), '}}', true, ([, ns = []], rest) => [[(0, dom_1.html)('span', {
5015
5014
  class: 'template'
5016
- }, `{{${ns.join('')}}}`)], rest], undefined, 3 | 28 /* Backtrack.template */)));
5017
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')'), (0, source_1.str)(')'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']'), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.escsource, /^["\n]/)), (0, source_1.str)('"'), true, undefined, undefined, 3 | 28 /* Backtrack.template */)])));
5015
+ }, `{{${ns.join('')}}}`)], rest], undefined, 3 | 32 /* Backtrack.template */)));
5016
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')'), (0, source_1.str)(')'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 32 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']'), (0, source_1.str)(']'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 32 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), (0, source_1.str)('}'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 32 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.escsource, /^["\n]/)), (0, source_1.str)('"'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 32 /* Backtrack.template */)])));
5018
5017
 
5019
5018
  /***/ },
5020
5019
 
@@ -5143,16 +5142,16 @@ const visibility_1 = __webpack_require__(6364);
5143
5142
  const dom_1 = __webpack_require__(394);
5144
5143
  exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(32 /* State.index */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, visibility_1.tightStart)((0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [['\n', 9], [']', 1]])))), ']', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('a', {
5145
5144
  'data-index': dataindex(ns)
5146
- }, (0, dom_1.defrag)(ns))], rest] : undefined, undefined, 1 | 8 /* Backtrack.bracket */)), ([el]) => [(0, dom_1.define)(el, {
5145
+ }, (0, dom_1.defrag)(ns))], rest] : undefined, undefined, 1 | 12 /* Backtrack.linebracket */, 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)), ([el]) => [(0, dom_1.define)(el, {
5147
5146
  id: el.id ? null : undefined,
5148
5147
  class: 'index',
5149
5148
  href: el.id ? `#${el.id}` : undefined
5150
5149
  })]))));
5151
- exports.signature = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('|', (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, combinator_1.open)(/^\|(?!\\?\s)/, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']')), ns => [(0, dom_1.html)('span', {
5150
+ exports.signature = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('|', (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, combinator_1.open)(/^\|(?!\\?\s)/, (0, combinator_1.some)((0, combinator_1.verify)((0, combinator_1.union)([bracket, source_1.txt]), ns => ns[0] !== "\u001B" /* Command.Escape */), ']')), ns => [(0, dom_1.html)('span', {
5152
5151
  class: 'indexer',
5153
5152
  'data-index': (0, indexee_1.identity)('index', undefined, ns.join('')).slice(7)
5154
5153
  })]))));
5155
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, undefined, undefined, 3 | 24 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, undefined, undefined, 3 | 24 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, undefined, undefined, 3 | 24 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 24 /* Backtrack.index */)])));
5154
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 28 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 28 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 28 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 28 /* Backtrack.index */)])));
5156
5155
  function dataindex(ns) {
5157
5156
  if (ns.length === 0) return;
5158
5157
  for (let i = ns.length - 1; i >= 0; --i) {
@@ -5751,7 +5750,7 @@ function context(base, parser) {
5751
5750
  exports.context = context;
5752
5751
  function apply(parser, source, context, changes, values, reset = false) {
5753
5752
  if (reset) {
5754
- context.logger = {};
5753
+ context.backtracks = {};
5755
5754
  }
5756
5755
  for (let i = 0; i < changes.length; ++i) {
5757
5756
  const change = changes[i];
@@ -5896,7 +5895,7 @@ exports.clear = exports.close = exports.open = exports.surround = void 0;
5896
5895
  const parser_1 = __webpack_require__(605);
5897
5896
  const fmap_1 = __webpack_require__(2705);
5898
5897
  const array_1 = __webpack_require__(6876);
5899
- function surround(opener, parser, closer, optional = false, f, g, log = 0) {
5898
+ function surround(opener, parser, closer, optional = false, f, g, backtrack = 0, bstate = 0) {
5900
5899
  switch (typeof opener) {
5901
5900
  case 'string':
5902
5901
  case 'object':
@@ -5920,22 +5919,30 @@ function surround(opener, parser, closer, optional = false, f, g, log = 0) {
5920
5919
  if (res1 === undefined) return;
5921
5920
  const rl = (0, parser_1.eval)(res1);
5922
5921
  const mr_ = (0, parser_1.exec)(res1);
5923
- if (log & 1) {
5922
+ if (backtrack & 1) {
5924
5923
  const {
5925
- logger = {},
5924
+ backtracks = {},
5925
+ backtrack: state = 0,
5926
5926
  offset = 0
5927
5927
  } = context;
5928
5928
  for (let i = 0; i < source.length - mr_.length; ++i) {
5929
5929
  if (source[i] !== source[0]) break;
5930
5930
  const pos = source.length + offset - i - 1;
5931
- if (!(pos in logger)) continue;
5932
- if (logger[pos] & 1 << (log >>> 2)) return;
5931
+ if (!(pos in backtracks)) continue;
5932
+ // bracket only
5933
+ const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
5934
+ if (backtracks[pos] & 1 << (backtrack >>> 2) + shift) return;
5933
5935
  }
5934
5936
  }
5937
+ const {
5938
+ backtrack: state = 0
5939
+ } = context;
5940
+ context.backtrack = state | bstate;
5935
5941
  const res2 = mr_ !== '' ? parser({
5936
5942
  source: mr_,
5937
5943
  context
5938
5944
  }) : undefined;
5945
+ context.backtrack = state;
5939
5946
  const rm = (0, parser_1.eval)(res2);
5940
5947
  const r_ = (0, parser_1.exec)(res2, mr_);
5941
5948
  if (!rm && !optional) return;
@@ -5946,12 +5953,15 @@ function surround(opener, parser, closer, optional = false, f, g, log = 0) {
5946
5953
  const rr = (0, parser_1.eval)(res3);
5947
5954
  const rest = (0, parser_1.exec)(res3, r_);
5948
5955
  if (rest.length === lmr_.length) return;
5949
- if (log & 2 && rr === undefined) {
5956
+ if (backtrack & 2 && rr === undefined) {
5950
5957
  const {
5951
- logger = {},
5958
+ backtracks = {},
5959
+ backtrack: state = 0,
5952
5960
  offset = 0
5953
5961
  } = context;
5954
- logger[source.length + offset - 1] |= 1 << (log >>> 2);
5962
+ // bracket only
5963
+ const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
5964
+ backtracks[source.length + offset - 1] |= 1 << (backtrack >>> 2) + shift;
5955
5965
  }
5956
5966
  return rr ? f ? f([rl, rm, rr], rest, context) : [(0, array_1.push)((0, array_1.unshift)(rl, rm ?? []), rr), rest] : g ? g([rl, rm, mr_], rest, context) : undefined;
5957
5967
  };
@@ -6483,14 +6493,14 @@ function convert(conv, parser, empty = false) {
6483
6493
  if (src === '') return empty ? [[], ''] : undefined;
6484
6494
  const sub = source.endsWith(src);
6485
6495
  const {
6486
- logger
6496
+ backtracks
6487
6497
  } = context;
6488
- context.logger = sub ? logger : {};
6498
+ context.backtracks = sub ? backtracks : {};
6489
6499
  const result = parser({
6490
6500
  source: src,
6491
6501
  context
6492
6502
  });
6493
- context.logger = logger;
6503
+ context.backtracks = backtracks;
6494
6504
  return result;
6495
6505
  };
6496
6506
  }
@@ -7091,14 +7101,14 @@ const source_1 = __webpack_require__(8745);
7091
7101
  const visibility_1 = __webpack_require__(6364);
7092
7102
  const array_1 = __webpack_require__(6876);
7093
7103
  const dom_1 = __webpack_require__(394);
7094
- exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, combinator_1.sequence)([(0, combinator_1.bind)((0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | 16 /* Backtrack.ruby */), ([source], rest, context) => {
7104
+ exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, combinator_1.sequence)([(0, combinator_1.bind)((0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | 20 /* Backtrack.ruby */), ([source], rest, context) => {
7095
7105
  const ns = (0, parser_1.eval)(text({
7096
7106
  source,
7097
7107
  context
7098
7108
  }), [undefined])[0];
7099
7109
  ns && ns.at(-1) === '' && ns.pop();
7100
7110
  return ns && (0, visibility_1.isTightNodeStart)(ns) ? [[ns], rest] : undefined;
7101
- }), (0, combinator_1.bind)((0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | 16 /* Backtrack.ruby */), ([source], rest, context) => {
7111
+ }), (0, combinator_1.bind)((0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | 20 /* Backtrack.ruby */), ([source], rest, context) => {
7102
7112
  const ns = (0, parser_1.eval)(text({
7103
7113
  source,
7104
7114
  context
@@ -7252,7 +7262,7 @@ const optspec = {
7252
7262
  rel: undefined
7253
7263
  };
7254
7264
  Object.setPrototypeOf(optspec, null);
7255
- exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* State.media */, false, (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.open)('!', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', [['\n', 9]])), ']', true, undefined, undefined, 1 | 12 /* Backtrack.media */)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/, false, undefined, undefined, 3 | 20 /* Backtrack.link */))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
7265
+ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* State.media */, false, (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.open)('!', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.verify)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ns => ns[0] !== "\u001B" /* Command.Escape */), ']', [['\n', 9]])), ']', true, undefined, undefined, 1 | 16 /* Backtrack.media */)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/, false, undefined, undefined, 3 | 24 /* Backtrack.link */))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
7256
7266
  const INSECURE_URI = params.shift();
7257
7267
  const url = new url_1.ReadonlyURL((0, link_1.resolve)(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location), context.host?.href || location.href);
7258
7268
  let cache;
@@ -7279,7 +7289,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* S
7279
7289
  });
7280
7290
  }))))));
7281
7291
  exports.linemedia = (0, combinator_1.surround)(source_1.linebreak, (0, combinator_1.union)([exports.media]), /^(?=[^\S\n]*(?:$|\n))/);
7282
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (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], 3 | 12 /* Backtrack.media */), (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], 3 | 12 /* Backtrack.media */), (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], 3 | 12 /* Backtrack.media */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 12 /* Backtrack.media */)])));
7292
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (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, () => [["\u001B" /* Command.Escape */], ''], 3 | 16 /* Backtrack.media */), (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, () => [["\u001B" /* Command.Escape */], ''], 3 | 16 /* Backtrack.media */), (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, () => [["\u001B" /* Command.Escape */], ''], 3 | 16 /* Backtrack.media */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true, undefined, () => [["\u001B" /* Command.Escape */], ''], 3 | 16 /* Backtrack.media */)])));
7283
7293
  const option = (0, combinator_1.lazy)(() => (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]));
7284
7294
  function sanitize(target, uri, alt) {
7285
7295
  switch (uri.protocol) {
@@ -7745,14 +7755,14 @@ function rewrite(scope, parser) {
7745
7755
  } = input;
7746
7756
  if (source === '') return;
7747
7757
  const {
7748
- logger
7758
+ backtracks
7749
7759
  } = context;
7750
- context.logger = {};
7760
+ context.backtracks = {};
7751
7761
  //const { resources = { clock: 0 } } = context;
7752
7762
  //const clock = resources.clock;
7753
7763
  const res1 = scope(input);
7754
7764
  //resources.clock = clock;
7755
- context.logger = logger;
7765
+ context.backtracks = backtracks;
7756
7766
  if (res1 === undefined || (0, parser_1.exec)(res1).length >= source.length) return;
7757
7767
  const src = source.slice(0, source.length - (0, parser_1.exec)(res1).length);
7758
7768
  const offset = source.length - src.length;
@@ -8841,7 +8851,7 @@ const inline_1 = __webpack_require__(7973);
8841
8851
  const source_1 = __webpack_require__(8745);
8842
8852
  const visibility_1 = __webpack_require__(6364);
8843
8853
  const dom_1 = __webpack_require__(394);
8844
- exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('[[', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */ | 4 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [['\n', 9], [']', 1]]))]))), ']]', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, 1 | 8 /* Backtrack.bracket */))));
8854
+ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, false, (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('[[', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */ | 4 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [['\n', 9], [']', 1]]))]))), ']]', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, 1 | 12 /* Backtrack.linebracket */, 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */))));
8845
8855
  // Chicago-Style
8846
8856
  const abbr = (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?=[A-Z])(?:[0-9A-Za-z]'?|(?:[-.:]|\.?\??,? ?)(?!['\-.:?, ]))+/)]), /^\|?(?=]])|^\|[^\S\n]*/, true, ([, ns], rest) => ns ? [['\n', ns[0].trimEnd()], rest.replace(visibility_1.blank.start, '')] : [[''], `^${rest}`], ([,, rest]) => [[''], `^${rest}`]));
8847
8857
  function attributes(ns) {
package/markdown.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Parser, Ctx } from './src/combinator/data/parser';
2
+ import { Command } from './src/parser/context';
2
3
  import { Dict } from 'spica/dict';
3
4
 
4
5
  declare abstract class Markdown<T> {
@@ -1196,8 +1197,8 @@ export namespace MarkdownParser {
1196
1197
  }
1197
1198
  export interface BracketParser extends
1198
1199
  Inline<'url/bracket'>,
1199
- Parser<string, Context, [
1200
- Parser<string, Context, [
1200
+ Parser<string | Command.Escape, Context, [
1201
+ Parser<string | Command.Escape, Context, [
1201
1202
  BracketParser,
1202
1203
  SourceParser.UnescapableSourceParser,
1203
1204
  ]>,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.285.0",
3
+ "version": "0.285.1",
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",
@@ -1,8 +1,8 @@
1
1
  import { isArray } from 'spica/alias';
2
2
  import { Parser, Input, Ctx, Tree, Context, eval, exec, check } from '../../data/parser';
3
3
 
4
- //export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (results: readonly Data<P>[], rest: string) => boolean): P;
5
- //export function contract<T>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<T>, cond: (results: readonly T[], rest: string) => boolean): Parser<T> {
4
+ //export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
5
+ //export function contract<T>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<T>, cond: (nodes: readonly T[], rest: string) => boolean): Parser<T> {
6
6
  // return verify(validate(patterns, parser), cond);
7
7
  //}
8
8
 
@@ -45,8 +45,8 @@ function guard<T>(f: (input: Input<Ctx>) => boolean, parser: Parser<T>): Parser<
45
45
  : undefined;
46
46
  }
47
47
 
48
- export function verify<P extends Parser<unknown>>(parser: P, cond: (results: readonly Tree<P>[], rest: string, context: Context<P>) => boolean): P;
49
- export function verify<T>(parser: Parser<T>, cond: (results: readonly T[], rest: string, context: Ctx) => boolean): Parser<T> {
48
+ export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: readonly Tree<P>[], rest: string, context: Context<P>) => boolean): P;
49
+ export function verify<T>(parser: Parser<T>, cond: (nodes: readonly T[], rest: string, context: Ctx) => boolean): Parser<T> {
50
50
  assert(parser);
51
51
  return input => {
52
52
  const { source, context } = input;
@@ -8,11 +8,11 @@ export function convert<T>(conv: (source: string, context: Ctx) => string, parse
8
8
  const src = conv(source, context);
9
9
  if (src === '') return empty ? [[], ''] : undefined;
10
10
  const sub = source.endsWith(src);
11
- const { logger } = context;
12
- context.logger = sub ? logger : {};
11
+ const { backtracks } = context;
12
+ context.backtracks = sub ? backtracks : {};
13
13
  const result = parser({ source: src, context });
14
14
  assert(check(src, result));
15
- context.logger = logger;
15
+ context.backtracks = backtracks;
16
16
  return result;
17
17
  };
18
18
  }
@@ -20,10 +20,10 @@ export function indent<T>(opener: RegExp | Parser<T>, parser?: Parser<T> | boole
20
20
  ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
21
21
  (lines, rest, context) => {
22
22
  assert(parser = parser as Parser<T>);
23
- const { logger } = context;
24
- context.logger = {};
23
+ const { backtracks } = context;
24
+ context.backtracks = {};
25
25
  const result = parser({ source: trimBlockEnd(lines.join('')), context });
26
- context.logger = logger;
26
+ context.backtracks = backtracks;
27
27
  return result && exec(result) === ''
28
28
  ? [eval(result), rest]
29
29
  : undefined;
@@ -35,14 +35,14 @@ export function rewrite<T>(scope: Parser<unknown>, parser: Parser<T>): Parser<T>
35
35
  return input => {
36
36
  const { source, context } = input;
37
37
  if (source === '') return;
38
- const { logger } = context;
39
- context.logger = {};
38
+ const { backtracks } = context;
39
+ context.backtracks = {};
40
40
  //const { resources = { clock: 0 } } = context;
41
41
  //const clock = resources.clock;
42
42
  const res1 = scope(input);
43
43
  assert(check(source, res1));
44
44
  //resources.clock = clock;
45
- context.logger = logger;
45
+ context.backtracks = backtracks;
46
46
  if (res1 === undefined || exec(res1).length >= source.length) return;
47
47
  const src = source.slice(0, source.length - exec(res1).length);
48
48
  assert(src !== '');
@@ -7,35 +7,40 @@ export function surround<P extends Parser<unknown>, S = string>(
7
7
  optional?: false,
8
8
  f?: (rss: [S[], SubTree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
9
9
  g?: (rss: [S[], SubTree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
10
- log?: number,
10
+ backtrack?: number,
11
+ bstate?: number,
11
12
  ): P;
12
13
  export function surround<P extends Parser<unknown>, S = string>(
13
14
  opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
14
15
  optional?: boolean,
15
16
  f?: (rss: [S[], SubTree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
16
17
  g?: (rss: [S[], SubTree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
17
- log?: number,
18
+ backtrack?: number,
19
+ bstate?: number,
18
20
  ): P;
19
21
  export function surround<P extends Parser<unknown>, S = string>(
20
22
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
21
23
  optional?: false,
22
24
  f?: (rss: [S[], Tree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
23
25
  g?: (rss: [S[], Tree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
24
- log?: number,
26
+ backtrack?: number,
27
+ bstate?: number,
25
28
  ): P;
26
29
  export function surround<P extends Parser<unknown>, S = string>(
27
30
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
28
31
  optional?: boolean,
29
32
  f?: (rss: [S[], Tree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
30
33
  g?: (rss: [S[], Tree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
31
- log?: number,
34
+ backtrack?: number,
35
+ bstate?: number,
32
36
  ): P;
33
37
  export function surround<T>(
34
38
  opener: string | RegExp | Parser<T>, parser: Parser<T>, closer: string | RegExp | Parser<T>,
35
39
  optional: boolean = false,
36
40
  f?: (rss: [T[], T[], T[]], rest: string, context: Ctx) => Result<T>,
37
41
  g?: (rss: [T[], T[], string], rest: string, context: Ctx) => Result<T>,
38
- log: number = 0,
42
+ backtrack: number = 0,
43
+ bstate: number = 0,
39
44
  ): Parser<T> {
40
45
  switch (typeof opener) {
41
46
  case 'string':
@@ -55,18 +60,23 @@ export function surround<T>(
55
60
  if (res1 === undefined) return;
56
61
  const rl = eval(res1);
57
62
  const mr_ = exec(res1);
58
- if (log & 1) {
59
- const { logger = {}, offset = 0 } = context;
63
+ if (backtrack & 1) {
64
+ const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
60
65
  for (let i = 0; i < source.length - mr_.length; ++i) {
61
66
  if (source[i] !== source[0]) break;
62
67
  const pos = source.length + offset - i - 1;
63
- if (!(pos in logger)) continue;
64
- assert(log >>> 2);
65
- if (logger[pos] & 1 << (log >>> 2)) return;
68
+ if (!(pos in backtracks)) continue;
69
+ assert(backtrack >>> 2);
70
+ // bracket only
71
+ const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
72
+ if (backtracks[pos] & 1 << (backtrack >>> 2) + shift) return;
66
73
  }
67
74
  }
75
+ const { backtrack: state = 0 } = context;
76
+ context.backtrack = state | bstate;
68
77
  const res2 = mr_ !== '' ? parser({ source: mr_, context }) : undefined;
69
78
  assert(check(mr_, res2));
79
+ context.backtrack = state;
70
80
  const rm = eval(res2);
71
81
  const r_ = exec(res2, mr_);
72
82
  if (!rm && !optional) return;
@@ -75,9 +85,11 @@ export function surround<T>(
75
85
  const rr = eval(res3);
76
86
  const rest = exec(res3, r_);
77
87
  if (rest.length === lmr_.length) return;
78
- if (log & 2 && rr === undefined) {
79
- const { logger = {}, offset = 0 } = context;
80
- logger[source.length + offset - 1] |= 1 << (log >>> 2);
88
+ if (backtrack & 2 && rr === undefined) {
89
+ const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
90
+ // bracket only
91
+ const shift = backtrack >>> 2 === state >>> 2 ? state & 3 : 0;
92
+ backtracks[source.length + offset - 1] |= 1 << (backtrack >>> 2) + shift;
81
93
  }
82
94
  return rr
83
95
  ? f
@@ -25,7 +25,7 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
25
25
  function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Tree<P>>;
26
26
  function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<T> {
27
27
  if (reset) {
28
- context.logger = {};
28
+ context.backtracks = {};
29
29
  }
30
30
  for (let i = 0; i < changes.length; ++i) {
31
31
  const change = changes[i];
@@ -18,6 +18,7 @@ export function some<T>(parser: Parser<T>, end?: string | RegExp | number, delim
18
18
  }));
19
19
  return ({ source, context }) => {
20
20
  if (source === '') return;
21
+ assert(context.backtracks ??= {});
21
22
  let rest = source;
22
23
  let nodes: T[] | undefined;
23
24
  if (delims.length > 0) {
@@ -19,7 +19,8 @@ export interface Ctx {
19
19
  precedence?: number;
20
20
  delimiters?: Delimiters;
21
21
  state?: number;
22
- logger?: Record<number, number>;
22
+ backtracks?: Record<number, number>;
23
+ backtrack?: number;
23
24
  }
24
25
  export type Tree<P extends Parser<unknown>> = P extends Parser<infer T> ? T : never;
25
26
  export type SubParsers<P extends Parser<unknown>> = P extends Parser<unknown, Ctx, infer D> ? D : never;
@@ -297,26 +297,26 @@ describe('Unit: parser/api/parse', () => {
297
297
  `<pre class="error" translate="no">${'{'.repeat(21)}a</pre>`,
298
298
  ]);
299
299
  assert.deepStrictEqual(
300
- [...parse(`${'('.repeat(22)}a`).children].map(el => el.outerHTML),
301
- [`<p>${'('.repeat(22)}a</p>`]);
300
+ [...parse(`${'('.repeat(20)}a`).children].map(el => el.outerHTML),
301
+ [`<p>${'('.repeat(20)}a</p>`]);
302
302
  assert.deepStrictEqual(
303
- [...parse(`${'('.repeat(23)}a`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
303
+ [...parse(`${'('.repeat(21)}a`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
304
304
  [
305
305
  '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
306
- `<pre class="error" translate="no">${'('.repeat(23)}a</pre>`,
306
+ `<pre class="error" translate="no">${'('.repeat(21)}a</pre>`,
307
307
  ]);
308
308
  assert.deepStrictEqual(
309
- [...parse(`${'['.repeat(23)}a`).children].map(el => el.outerHTML),
310
- [`<p>${'['.repeat(23)}a</p>`]);
309
+ [...parse(`${'['.repeat(20)}a`).children].map(el => el.outerHTML),
310
+ [`<p>${'['.repeat(20)}a</p>`]);
311
311
  assert.deepStrictEqual(
312
- [...parse(`${'['.repeat(24)}a`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
312
+ [...parse(`${'['.repeat(21)}a`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
313
313
  [
314
314
  '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
315
- `<pre class="error" translate="no">${'['.repeat(24)}a</pre>`,
315
+ `<pre class="error" translate="no">${'['.repeat(21)}a</pre>`,
316
316
  ]);
317
317
  assert.deepStrictEqual(
318
- [...parse(`${'['.repeat(22)}\na`).children].map(el => el.outerHTML),
319
- [`<p>${'['.repeat(22)}<br>a</p>`]);
318
+ [...parse(`${'['.repeat(20)}\na`).children].map(el => el.outerHTML),
319
+ [`<p>${'['.repeat(20)}<br>a</p>`]);
320
320
  });
321
321
 
322
322
  it('recovery', () => {
@@ -351,17 +351,17 @@ describe('Unit: parser/api/parse', () => {
351
351
  it('backtrack', function () {
352
352
  this.timeout(5000);
353
353
  assert.deepStrictEqual(
354
- [...parse(`(({{${'['.repeat(19)}${'.'.repeat(3301)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
355
- [`<p>(({{${'['.repeat(19)}${'.'.repeat(3301)}</p>`]);
354
+ [...parse(`(({{${'['.repeat(15)}http://[${'.'.repeat(1802)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
355
+ [`<p>(({{${'['.repeat(15)}http://[${'.'.repeat(1802)}</p>`]);
356
356
  });
357
357
 
358
358
  it('backtrack error', function () {
359
359
  this.timeout(5000);
360
360
  assert.deepStrictEqual(
361
- [...parse(`(({{${'['.repeat(19)}${'.'.repeat(3302)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
361
+ [...parse(`(({{${'['.repeat(15)}http://[${'.'.repeat(1803)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
362
362
  [
363
363
  '<h1 id="error:rnd" class="error">Error: Too many creations</h1>',
364
- `<pre class="error" translate="no">(({{${'['.repeat(19)}${'.'.repeat(1000 - 4 - 19 - 3)}...</pre>`,
364
+ `<pre class="error" translate="no">(({{${'['.repeat(15)}http://[${'.'.repeat(1000 - 4 - 15 - 8 - 3)}...</pre>`,
365
365
  ]);
366
366
  });
367
367
 
@@ -29,14 +29,19 @@ export const enum Recursion {
29
29
  }
30
30
 
31
31
  export const enum Backtrack {
32
- template = 7 << 2,
33
- index = 6 << 2,
34
- link = 5 << 2,
35
- ruby = 4 << 2,
36
- media = 3 << 2,
32
+ template = 8 << 2,
33
+ index = 7 << 2,
34
+ link = 6 << 2,
35
+ ruby = 5 << 2,
36
+ media = 4 << 2,
37
+ linebracket = 3 << 2,
37
38
  bracket = 2 << 2,
38
39
  url = 1 << 2,
39
40
  }
41
+ export const enum BacktrackState {
42
+ nobreak = 1,
43
+ }
44
+ assert(Backtrack.linebracket === Backtrack.bracket + (BacktrackState.nobreak << 2));
40
45
 
41
46
  export const enum Command {
42
47
  Error = '\x07',
@@ -1,5 +1,5 @@
1
1
  import { AnnotationParser } from '../inline';
2
- import { State, Recursion, Backtrack } from '../context';
2
+ import { State, Recursion, Backtrack, BacktrackState } from '../context';
3
3
  import { union, some, creation, precedence, state, constraint, surround, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
@@ -15,4 +15,4 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
15
15
  trimBlankNodeEnd(ns).length > 0
16
16
  ? [[html('sup', { class: 'annotation' }, [html('span', defrag(ns))])], rest]
17
17
  : undefined,
18
- undefined, 1 | Backtrack.bracket))));
18
+ undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak))));
@@ -1,6 +1,6 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State, Recursion, Backtrack } from '../../context';
3
- import { union, tails, some, creation, precedence, state, constraint, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
2
+ import { State, Recursion, Backtrack, Command } from '../../context';
3
+ import { union, tails, some, creation, precedence, state, constraint, validate, verify, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
4
4
  import { unsafelink } from '../link';
5
5
  import { linebreak, unescsource, str } from '../../source';
6
6
 
@@ -9,7 +9,10 @@ const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
9
9
  export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'https://'], rewrite(
10
10
  open(
11
11
  /^https?:\/\/(?=[\x21-\x7E])/,
12
- focus(/^[\x21-\x7E]+/, precedence(1, some(union([bracket, some(unescsource, closer)]))))),
12
+ focus(/^[\x21-\x7E]+/, precedence(1, some(verify(union([
13
+ bracket,
14
+ some(unescsource, closer),
15
+ ]), ns => ns[0] !== Command.Escape))))),
13
16
  union([
14
17
  constraint(State.autolink, false, state(State.autolink, convert(
15
18
  url => `{ ${url} }`,
@@ -32,8 +35,12 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
32
35
  ]))));
33
36
 
34
37
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
35
- surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.url),
36
- surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.url),
37
- surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.url),
38
- surround(str('"'), precedence(2, some(unescsource, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.url),
38
+ surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true,
39
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.url),
40
+ surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true,
41
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.url),
42
+ surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true,
43
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.url),
44
+ surround(str('"'), precedence(2, some(unescsource, '"')), str('"'), true,
45
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.url),
39
46
  ])));
@@ -1,6 +1,6 @@
1
1
  import { ExtensionParser } from '../../inline';
2
- import { State, Recursion, Backtrack } from '../../context';
3
- import { union, inits, some, creation, precedence, state, constraint, validate, surround, open, lazy, fmap } from '../../../combinator';
2
+ import { State, Recursion, Backtrack, BacktrackState, Command } from '../../context';
3
+ import { union, inits, some, creation, precedence, state, constraint, validate, verify, surround, open, lazy, fmap } from '../../../combinator';
4
4
  import { inline } from '../../inline';
5
5
  import { indexee, identity } from './indexee';
6
6
  import { txt, str } from '../../source';
@@ -23,7 +23,7 @@ export const index: IndexParser = lazy(() => constraint(State.index, false, crea
23
23
  trimBlankNodeEnd(ns).length > 0
24
24
  ? [[html('a', { 'data-index': dataindex(ns) }, defrag(ns))], rest]
25
25
  : undefined,
26
- undefined, 1 | Backtrack.bracket)),
26
+ undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak)),
27
27
  ([el]: [HTMLAnchorElement]) => [
28
28
  define(el,
29
29
  {
@@ -35,16 +35,20 @@ export const index: IndexParser = lazy(() => constraint(State.index, false, crea
35
35
 
36
36
  export const signature: IndexParser.SignatureParser = lazy(() => validate('|', creation(1, Recursion.ignore, fmap(open(
37
37
  /^\|(?!\\?\s)/,
38
- some(union([bracket, txt]), ']')),
38
+ some(verify(union([bracket, txt]), ns => ns[0] !== Command.Escape), ']')),
39
39
  ns => [
40
40
  html('span', { class: 'indexer', 'data-index': identity('index', undefined, ns.join(''))!.slice(7) }),
41
41
  ]))));
42
42
 
43
43
  const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
44
- surround(str('('), some(union([bracket, txt]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.index),
45
- surround(str('['), some(union([bracket, txt]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.index),
46
- surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.index),
47
- surround(str('"'), precedence(2, some(txt, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.index),
44
+ surround(str('('), some(union([bracket, txt]), ')'), str(')'), true,
45
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
46
+ surround(str('['), some(union([bracket, txt]), ']'), str(']'), true,
47
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
48
+ surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true,
49
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
50
+ surround(str('"'), precedence(2, some(txt, '"')), str('"'), true,
51
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.index),
48
52
  ])));
49
53
 
50
54
  export function dataindex(ns: readonly (string | HTMLElement)[]): string | undefined {
@@ -1,6 +1,6 @@
1
1
  import { MarkdownParser } from '../../../markdown';
2
2
  import { LinkParser } from '../inline';
3
- import { State, Recursion, Backtrack } from '../context';
3
+ import { State, Recursion, Backtrack, BacktrackState } from '../context';
4
4
  import { union, inits, tails, sequence, some, creation, precedence, state, constraint, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
@@ -22,7 +22,7 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
22
22
  '[',
23
23
  trimBlankStart(some(union([inline]), ']', [['\n', 9], [']', 1]])),
24
24
  ']',
25
- true, undefined, undefined, 1 | Backtrack.bracket)),
25
+ true, undefined, undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak)),
26
26
  dup(surround(
27
27
  /^{(?![{}])/,
28
28
  inits([uri, some(option)]),
@@ -7,7 +7,7 @@ import { unsafehtmlentity } from './htmlentity';
7
7
  import { txt, linebreak, str } from '../source';
8
8
  import { markInvalid } from '../util';
9
9
  import { ReadonlyURL } from 'spica/url';
10
- import { unshift, push } from 'spica/array';
10
+ import { push } from 'spica/array';
11
11
  import { html, define } from 'typed-dom/dom';
12
12
 
13
13
  const optspec = {
@@ -23,7 +23,11 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
23
23
  bind(verify(fmap(tails([
24
24
  dup(surround(
25
25
  '[',
26
- precedence(1, some(union([unsafehtmlentity, bracket, txt]), ']', [['\n', 9]])),
26
+ precedence(1, some(verify(union([
27
+ unsafehtmlentity,
28
+ bracket,
29
+ txt,
30
+ ]), ns => ns[0] !== Command.Escape), ']', [['\n', 9]])),
27
31
  ']',
28
32
  true, undefined, undefined, 1 | Backtrack.media)),
29
33
  dup(surround(
@@ -71,13 +75,13 @@ export const linemedia: MediaParser.LineMediaParser = surround(
71
75
 
72
76
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
73
77
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true,
74
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
78
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
75
79
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true,
76
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
80
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
77
81
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
78
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
82
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
79
83
  surround(str('"'), precedence(2, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
80
- undefined, undefined, 3 | Backtrack.media),
84
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.media),
81
85
  ])));
82
86
 
83
87
  const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
@@ -1,5 +1,5 @@
1
1
  import { ReferenceParser } from '../inline';
2
- import { State, Recursion, Backtrack } from '../context';
2
+ import { State, Recursion, Backtrack, BacktrackState } from '../context';
3
3
  import { union, subsequence, some, creation, precedence, state, constraint, surround, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
@@ -19,7 +19,7 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
19
19
  trimBlankNodeEnd(ns).length > 0
20
20
  ? [[html('sup', attributes(ns), [html('span', defrag(ns))])], rest]
21
21
  : undefined,
22
- undefined, 1 | Backtrack.bracket))));
22
+ undefined, 1 | Backtrack.linebracket, Backtrack.bracket | BacktrackState.nobreak))));
23
23
 
24
24
  // Chicago-Style
25
25
  const abbr: ReferenceParser.AbbrParser = creation(1, Recursion.ignore, surround(
@@ -1,13 +1,12 @@
1
1
  import { TemplateParser } from '../inline';
2
- import { Recursion, Backtrack } from '../context';
3
- import { union, some, creation, precedence, surround, lazy } from '../../combinator';
2
+ import { Recursion, Backtrack, Command } from '../context';
3
+ import { union, some, creation, precedence, verify, surround, lazy } from '../../combinator';
4
4
  import { escsource, str } from '../source';
5
- import { unshift } from 'spica/array';
6
5
  import { html } from 'typed-dom/dom';
7
6
 
8
7
  export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore, surround(
9
8
  '{{',
10
- precedence(1, some(union([bracket, escsource]), '}')),
9
+ precedence(1, some(verify(union([bracket, escsource]), ns => ns[0] !== Command.Escape), '}')),
11
10
  '}}',
12
11
  true,
13
12
  ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('')}}}`)], rest],
@@ -15,11 +14,11 @@ export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore,
15
14
 
16
15
  const bracket: TemplateParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
17
16
  surround(str('('), some(union([bracket, escsource]), ')'), str(')'), true,
18
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
17
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
19
18
  surround(str('['), some(union([bracket, escsource]), ']'), str(']'), true,
20
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
19
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
21
20
  surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true,
22
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
21
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
23
22
  surround(str('"'), precedence(2, some(escsource, /^["\n]/)), str('"'), true,
24
- undefined, undefined, 3 | Backtrack.template),
23
+ undefined, () => [[Command.Escape], ''], 3 | Backtrack.template),
25
24
  ])));
@@ -126,6 +126,7 @@ describe('Unit: parser/inline', () => {
126
126
  assert.deepStrictEqual(inspect(parser('((((a))))')), [['<sup class="annotation"><span><span class="paren">((a))</span></span></sup>'], '']);
127
127
  assert.deepStrictEqual(inspect(parser('((${))}$')), [['(', '(', '<span class="math" translate="no" data-src="${))}$">${))}$</span>'], '']);
128
128
  assert.deepStrictEqual(inspect(parser('((a\nb))')), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
129
+ assert.deepStrictEqual(inspect(parser('(((a\nb)))')), [['<span class="paren">(<span class="paren">(<span class="paren">(a<br>b)</span>)</span>)</span>'], '']);
129
130
  assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '(', '(', '"', '"', ')', ')'], '']);
130
131
  assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
131
132
  assert.deepStrictEqual(inspect(parser('[[[[a]]')), [['[', '[', '<sup class="reference"><span>a</span></sup>'], '']);
@@ -135,6 +136,8 @@ describe('Unit: parser/inline', () => {
135
136
  assert.deepStrictEqual(inspect(parser('[[[a]{b}]]')), [['<sup class="reference"><span><a class="link" href="b">a</a></span></sup>'], '']);
136
137
  assert.deepStrictEqual(inspect(parser('[(([a]{#}))]{#}')), [['<a class="link" href="#"><span class="paren">(<span class="paren">([a]{#})</span>)</span></a>'], '']);
137
138
  assert.deepStrictEqual(inspect(parser('[[${]]}$')), [['[', '[', '<span class="math" translate="no" data-src="${]]}$">${]]}$</span>'], '']);
139
+ assert.deepStrictEqual(inspect(parser('[[a\nb]]')), [['[', '[', 'a', '<br>', 'b', ']', ']'], '']);
140
+ assert.deepStrictEqual(inspect(parser('[[[a\nb]]]')), [['[', '[', '[', 'a', '<br>', 'b', ']', ']', ']'], '']);
138
141
  assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '[', '[', '"', '"', ']', ']'], '']);
139
142
  assert.deepStrictEqual(inspect(parser('[==a==]{b}')), [['<a class="link" href="b">==a==</a>'], '']);
140
143
  assert.deepStrictEqual(inspect(parser('[[a](b)]{c}')), [['<a class="link" href="c"><ruby>a<rp>(</rp><rt>b</rt><rp>)</rp></ruby></a>'], '']);