securemark 0.299.0 → 0.299.2

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.299.2
4
+
5
+ - Refactoring.
6
+
7
+ ## 0.299.1
8
+
9
+ - Refactoring.
10
+
3
11
  ## 0.299.0
4
12
 
5
13
  - Add support for CRLF linebreaks.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.299.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.299.2 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"));
@@ -3745,16 +3745,21 @@ Object.defineProperty(exports, "__esModule", ({
3745
3745
  }));
3746
3746
  exports.some = void 0;
3747
3747
  const delimiter_1 = __webpack_require__(385);
3748
- function some(parser, delimiter, after, delimiters, limit = -1) {
3748
+ function some(parser, delimiter, after, delimiters, limit = 0) {
3749
3749
  if (typeof delimiter === 'number') {
3750
3750
  limit = delimiter;
3751
+ delimiters = undefined;
3751
3752
  delimiter = undefined;
3752
3753
  } else if (Array.isArray(delimiter)) {
3754
+ limit = after;
3753
3755
  delimiters = delimiter;
3754
3756
  delimiter = undefined;
3755
3757
  } else if (after === undefined || Array.isArray(after)) {
3758
+ limit = delimiters;
3756
3759
  delimiters = after;
3757
3760
  after = undefined;
3761
+ } else {
3762
+ delimiters = delimiters;
3758
3763
  }
3759
3764
  const match = delimiter_1.Delimiters.tester(delimiter, after);
3760
3765
  const delims = delimiters?.map(([delimiter, precedence]) => ({
@@ -3780,7 +3785,8 @@ function some(parser, delimiter, after, delimiters, limit = -1) {
3780
3785
  if (result === undefined) break;
3781
3786
  if (context.position === pos) break;
3782
3787
  nodes = nodes?.import(result) ?? result;
3783
- if (limit >= 0 && context.position - position > limit) break;
3788
+ // 次にパースに成功すれば確実に制限値を超えるので制限値ちょうどでも中止する
3789
+ if (limit > 0 && context.position - position >= limit) break;
3784
3790
  }
3785
3791
  delims && context.delimiters.pop(delims.length);
3786
3792
  return context.position > position ? nodes : undefined;
@@ -4201,7 +4207,11 @@ function header(source) {
4201
4207
  exports.header = header;
4202
4208
  function headers(source) {
4203
4209
  const [el] = parse(source);
4204
- return el?.textContent.trimEnd().slice(el.firstChild.firstChild.textContent.length).split(/\r?\n/) ?? [];
4210
+ const acc = [];
4211
+ for (let field = el?.firstChild?.firstChild; field = field?.nextSibling;) {
4212
+ acc.push(field.textContent);
4213
+ }
4214
+ return acc;
4205
4215
  }
4206
4216
  exports.headers = headers;
4207
4217
  function parse(source) {
@@ -4224,7 +4234,7 @@ function parse(source) {
4224
4234
  Object.defineProperty(exports, "__esModule", ({
4225
4235
  value: true
4226
4236
  }));
4227
- exports.escape = exports.invisibleGraphHTMLEntityNames = exports.invisibleBlankCharacters = exports.invisibleBlankHTMLEntityNames = exports.normalize = void 0;
4237
+ exports.escape = exports.invisibleGraphHTMLEntityNames = exports.invisibleBlankHTMLEntityNames = exports.normalize = void 0;
4228
4238
  const dom_1 = __webpack_require__(394);
4229
4239
  const UNICODE_REPLACEMENT_CHARACTER = '\uFFFD';
4230
4240
  function normalize(source) {
@@ -4251,7 +4261,6 @@ const parser = (el => entity => {
4251
4261
  return el.textContent;
4252
4262
  })((0, dom_1.html)('span'));
4253
4263
  exports.invisibleBlankHTMLEntityNames = invisibleHTMLEntityNames.filter(name => parser(`&${name};`).trimStart() === '');
4254
- exports.invisibleBlankCharacters = exports.invisibleBlankHTMLEntityNames.map(name => parser(`&${name};`));
4255
4264
  exports.invisibleGraphHTMLEntityNames = invisibleHTMLEntityNames.filter(name => parser(`&${name};`).trimStart() !== '');
4256
4265
  const unreadableEscapeHTMLEntityNames = invisibleHTMLEntityNames.filter(name => !['Tab', 'NewLine', 'NonBreakingSpace', 'nbsp', 'zwj', 'zwnj'].includes(name));
4257
4266
  const unreadableEscapeCharacters = unreadableEscapeHTMLEntityNames.map(name => parser(`&${name};`));
@@ -5828,7 +5837,7 @@ class Context extends parser_1.Context {
5828
5837
  } = options;
5829
5838
  this.resources ??= {
5830
5839
  // バックトラックのせいで文字数制限を受けないようにする。
5831
- clock: exports.MAX_SEGMENT_SIZE * (6 + 1),
5840
+ clock: exports.MAX_SEGMENT_SIZE * (5 + 1),
5832
5841
  recursions: [5 || 0 /* Recursion.block */, 20 || 0 /* Recursion.blockquote */, 40 || 0 /* Recursion.listitem */, 20 || 0 /* Recursion.inline */, 20 || 0 /* Recursion.bracket */, 20 || 0 /* Recursion.terminal */]
5833
5842
  };
5834
5843
  this.segment = segment ?? 0 /* Segment.unknown */;
@@ -5882,7 +5891,7 @@ const combinator_1 = __webpack_require__(3484);
5882
5891
  const source_1 = __webpack_require__(8745);
5883
5892
  const util_1 = __webpack_require__(4992);
5884
5893
  const dom_1 = __webpack_require__(394);
5885
- exports.header = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/---+[^\S\r\n]*\r?\n(?=\S)/y, (0, combinator_1.inits)([(0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.validate)(context => context.header, (0, combinator_1.focus)(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,100}\1[^\S\r\n]*(?:$|\r?\n)/yi, (0, combinator_1.convert)(source => source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')), (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.union)([field])), ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('aside', {
5894
+ exports.header = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/---+[^\S\r\n]*\r?\n(?=\S)/y, (0, combinator_1.inits)([(0, combinator_1.block)((0, combinator_1.union)([(0, combinator_1.validate)(context => context.header, (0, combinator_1.focus)(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi, (0, combinator_1.convert)(source => source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')), (0, combinator_1.fmap)((0, combinator_1.some)((0, combinator_1.union)([field])), ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('aside', {
5886
5895
  class: 'header'
5887
5896
  }, [(0, dom_1.html)('details', {
5888
5897
  open: ''
@@ -5904,7 +5913,7 @@ const field = (0, combinator_1.line)(({
5904
5913
  }) => {
5905
5914
  const name = source.slice(position, source.indexOf(':', position));
5906
5915
  const value = source.slice(position + name.length + 1).trim();
5907
- return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
5916
+ return new parser_1.List([new parser_1.Node((0, dom_1.html)('div', {
5908
5917
  class: 'field',
5909
5918
  'data-name': name.toLowerCase(),
5910
5919
  'data-value': value
@@ -5912,7 +5921,7 @@ const field = (0, combinator_1.line)(({
5912
5921
  class: 'field-name'
5913
5922
  }, name), ': ', (0, dom_1.html)('span', {
5914
5923
  class: 'field-value'
5915
- }, value), '\n']))]);
5924
+ }, value)]))]);
5916
5925
  });
5917
5926
 
5918
5927
  /***/ },
@@ -6360,10 +6369,9 @@ Object.defineProperty(exports, "__esModule", ({
6360
6369
  exports.lineurl = exports.url = void 0;
6361
6370
  const parser_1 = __webpack_require__(605);
6362
6371
  const combinator_1 = __webpack_require__(3484);
6363
- const inline_1 = __webpack_require__(7973);
6364
6372
  const link_1 = __webpack_require__(3628);
6365
6373
  const source_1 = __webpack_require__(8745);
6366
- exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[\x21-\x7E])/y, (0, combinator_1.precedence)(0, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y), (0, combinator_1.precedence)(1, bracket)]), [[/[^\x21-\x7E]|\$/y, 9]])), false, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, context => new parser_1.List([new parser_1.Node((0, link_1.parse)(new parser_1.List(), new parser_1.List([new parser_1.Node(context.source)]), context))]))), (0, combinator_1.open)((0, source_1.str)(/[^:]+/y), (0, combinator_1.some)(inline_1.inline))])));
6374
+ exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)(/(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[[0-9A-Za-z])/y, (0, combinator_1.precedence)(0, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y), (0, combinator_1.precedence)(1, bracket)]), [[/[^\x21-\x7E]|\$/y, 9]])), false, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, context => new parser_1.List([new parser_1.Node((0, link_1.parse)(new parser_1.List(), new parser_1.List([new parser_1.Node(context.source)]), context))]))), context => new parser_1.List([new parser_1.Node(context.source)])])));
6367
6375
  exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.focus)(/(?<=^|[\r\n])!?https?:\/\/\S+(?=[^\S\r\n]*(?=$|\r?\n))/y, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, (0, combinator_1.state)(1 /* State.autolink */, context => {
6368
6376
  const {
6369
6377
  source,
@@ -6371,7 +6379,7 @@ exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.focus)(/(?<=^|[\
6371
6379
  } = context;
6372
6380
  context.position -= source[0] === '!' ? 1 : 0;
6373
6381
  return new parser_1.List([new parser_1.Node((0, link_1.parse)(new parser_1.List(), new parser_1.List([new parser_1.Node(source.slice(position))]), context))]);
6374
- })), (0, source_1.str)(/[^:]+/y)])])));
6382
+ })), context => new parser_1.List([new parser_1.Node(context.source)])])])));
6375
6383
  const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')')), (0, source_1.str)(')'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']')), (0, source_1.str)(']'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}')), (0, source_1.str)('}'), true, [3 | 8 /* Backtrack.unescapable */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)(source_1.unescsource, '"'))), (0, source_1.str)('"'), true, [3 | 8 /* Backtrack.unescapable */])]));
6376
6384
 
6377
6385
  /***/ },
@@ -7390,8 +7398,8 @@ const combinator_1 = __webpack_require__(3484);
7390
7398
  const source_1 = __webpack_require__(8745);
7391
7399
  const util_1 = __webpack_require__(4992);
7392
7400
  const dom_1 = __webpack_require__(394);
7393
- const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])|:\/\//i;
7394
- exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)(/\$(?={)/y, (0, combinator_1.precedence)(4, bracket), '$', false, [3 | 16 /* Backtrack.escapable */]), (0, combinator_1.surround)(/\$(?![\s{}])/y, (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.escsource, /\$|[`"{}\r\n]/y), (0, combinator_1.precedence)(4, bracket)]))), /(?<!\s)\$(?![-0-9A-Za-z])/y, false, [3 | 16 /* Backtrack.escapable */])]), ({
7401
+ const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
7402
+ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.union)([(0, combinator_1.surround)(/\$(?={)/y, (0, combinator_1.precedence)(4, bracket), '$', false, [3 | 16 /* Backtrack.escapable */]), (0, combinator_1.surround)(/\$(?![\s{}])/y, (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(source_1.escsource, /[`"{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y), (0, combinator_1.precedence)(4, bracket)]))), /(?<!\s)\$(?![-0-9A-Za-z])/y, false, [3 | 16 /* Backtrack.escapable */])]), ({
7395
7403
  source,
7396
7404
  caches: {
7397
7405
  math: cache
@@ -7405,7 +7413,7 @@ exports.math = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combin
7405
7413
  translate: 'no',
7406
7414
  ...(0, util_1.invalid)('math', 'content', `"${source.match(forbiddenCommand)[0]}" command is forbidden`)
7407
7415
  }, source))])));
7408
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.escsource, /[{}$\r\n]/y)]))), (0, source_1.str)('}'), true));
7416
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(5 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.escsource, /[{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y)]))), (0, source_1.str)('}'), true));
7409
7417
 
7410
7418
  /***/ },
7411
7419
 
@@ -7667,14 +7675,14 @@ const dom_1 = __webpack_require__(394);
7667
7675
  exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.inits)([(0, combinator_1.dup)((0, combinator_1.surround)('[', text, ']', false, [1 | 4 /* Backtrack.common */, 3 | 32 /* Backtrack.ruby */], ([, ns]) => {
7668
7676
  ns && ns.last?.value === '' && ns.pop();
7669
7677
  return (0, visibility_1.isNonblankNodeStart)(ns) ? ns : undefined;
7670
- })), (0, combinator_1.dup)((0, combinator_1.surround)('(', text, ')', false, [3 | 32 /* Backtrack.ruby */]))]), ([{
7678
+ })), (0, combinator_1.dup)((0, combinator_1.surround)('(', text, ')', false))]), ([{
7671
7679
  value: texts
7672
7680
  }, {
7673
7681
  value: rubies = undefined
7674
7682
  } = {}], context) => {
7675
7683
  if (rubies === undefined) {
7676
7684
  const head = context.position - context.range;
7677
- return void (0, combinator_1.setBacktrack)(context, 2 | 32 /* Backtrack.ruby */, head);
7685
+ return void (0, combinator_1.setBacktrack)(context, 2 | 64 /* Backtrack.link */ | 32 /* Backtrack.ruby */, head);
7678
7686
  }
7679
7687
  switch (true) {
7680
7688
  case texts.length >= rubies.length:
@@ -8210,10 +8218,10 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
8210
8218
  follow = follow > 0 ? follow : countFollows(source, pos, closer, lead / opener.length | 0);
8211
8219
  nodes = cons(nodes, context, lead, follow);
8212
8220
  if (context.position > pos) {
8213
- const advance = opener.length * (context.position - pos) / closer.length | 0;
8221
+ const advance = context.position - pos;
8214
8222
  i -= advance;
8215
8223
  follow -= advance;
8216
- depth -= advance;
8224
+ depth -= advance / closer.length | 0;
8217
8225
  }
8218
8226
  continue;
8219
8227
  }
@@ -8240,10 +8248,10 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
8240
8248
  nodes = cons(nodes, context, lead, follow);
8241
8249
  state = true;
8242
8250
  if (context.position > pos) {
8243
- const advance = opener.length * (context.position - pos) / closer.length | 0;
8251
+ const advance = context.position - pos;
8244
8252
  i -= advance;
8245
8253
  follow -= advance;
8246
- depth -= advance;
8254
+ depth -= advance / closer.length | 0;
8247
8255
  }
8248
8256
  continue;
8249
8257
  }
@@ -8432,14 +8440,11 @@ Object.defineProperty(exports, "__esModule", ({
8432
8440
  exports.escsource = void 0;
8433
8441
  const parser_1 = __webpack_require__(605);
8434
8442
  const combinator_1 = __webpack_require__(3484);
8435
- const text_1 = __webpack_require__(5655);
8436
8443
  const dom_1 = __webpack_require__(394);
8437
- const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
8438
8444
  const escsource = context => {
8439
8445
  const {
8440
8446
  source,
8441
- position,
8442
- state
8447
+ position
8443
8448
  } = context;
8444
8449
  if (position === source.length) return;
8445
8450
  const char = source[position];
@@ -8468,7 +8473,7 @@ const escsource = context => {
8468
8473
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('br'), 1 /* Flag.blank */)]);
8469
8474
  default:
8470
8475
  if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
8471
- let i = (0, text_1.next)(source, position, state, delimiter);
8476
+ let i = seek(source, position);
8472
8477
  i -= position;
8473
8478
  (0, combinator_1.consume)(i - 1, context);
8474
8479
  context.position += i - 1;
@@ -8476,6 +8481,30 @@ const escsource = context => {
8476
8481
  }
8477
8482
  };
8478
8483
  exports.escsource = escsource;
8484
+ function seek(source, position) {
8485
+ for (let i = position + 1; i < source.length; ++i) {
8486
+ const char = source[i];
8487
+ switch (char) {
8488
+ case '\\':
8489
+ case '$':
8490
+ case '"':
8491
+ case '`':
8492
+ case ':':
8493
+ case '[':
8494
+ case ']':
8495
+ case '(':
8496
+ case ')':
8497
+ case '{':
8498
+ case '}':
8499
+ case '\r':
8500
+ case '\n':
8501
+ return i;
8502
+ default:
8503
+ continue;
8504
+ }
8505
+ }
8506
+ return source.length;
8507
+ }
8479
8508
 
8480
8509
  /***/ },
8481
8510
 
@@ -8605,7 +8634,7 @@ exports.strs = strs;
8605
8634
  Object.defineProperty(exports, "__esModule", ({
8606
8635
  value: true
8607
8636
  }));
8608
- exports.isAlphanumeric = exports.next = exports.canSkip = exports.txt = exports.text = exports.nonWhitespace = void 0;
8637
+ exports.isAlphanumeric = exports.backToEmailHead = exports.backToUrlHead = exports.canSkip = exports.txt = exports.text = exports.nonWhitespace = void 0;
8609
8638
  const parser_1 = __webpack_require__(605);
8610
8639
  const combinator_1 = __webpack_require__(3484);
8611
8640
  const dom_1 = __webpack_require__(394);
@@ -8676,23 +8705,16 @@ function isWhitespace(char, linebreak) {
8676
8705
  return false;
8677
8706
  }
8678
8707
  }
8679
- function next(source, position, state, delimiter) {
8680
- let index;
8681
- if (delimiter) {
8682
- delimiter.lastIndex = position + 1;
8683
- delimiter.test(source);
8684
- index = delimiter.lastIndex || position;
8685
- } else {
8686
- index = seek(source, position, state);
8687
- }
8688
- if (index === position || index === source.length) return source.length;
8708
+ function next(source, position, state) {
8709
+ let index = seek(source, position, state);
8710
+ if (index === source.length) return source.length;
8689
8711
  const char = source[index];
8690
8712
  switch (char) {
8691
8713
  case '%':
8692
- index += !delimiter && index - 1 > position ? -1 : 0;
8714
+ index += index - 1 > position ? -1 : 0;
8693
8715
  break;
8694
8716
  case '[':
8695
- index += !delimiter && index - 1 > position && source.startsWith(' [|', index - 1) ? -1 : 0;
8717
+ index += index - 1 > position && source.startsWith(' [|', index - 1) ? -1 : 0;
8696
8718
  break;
8697
8719
  case ':':
8698
8720
  index = source.startsWith('//', index + 1) ? backToUrlHead(source, position, index) : index;
@@ -8703,7 +8725,6 @@ function next(source, position, state, delimiter) {
8703
8725
  }
8704
8726
  return index;
8705
8727
  }
8706
- exports.next = next;
8707
8728
  function backToUrlHead(source, position, index) {
8708
8729
  const delim = index;
8709
8730
  let state = false;
@@ -8725,6 +8746,7 @@ function backToUrlHead(source, position, index) {
8725
8746
  }
8726
8747
  return index === position || source[index] !== 'h' ? delim : index;
8727
8748
  }
8749
+ exports.backToUrlHead = backToUrlHead;
8728
8750
  function backToEmailHead(source, position, index) {
8729
8751
  const delim = index;
8730
8752
  let state = false;
@@ -8747,6 +8769,7 @@ function backToEmailHead(source, position, index) {
8747
8769
  }
8748
8770
  return index === position ? delim : index;
8749
8771
  }
8772
+ exports.backToEmailHead = backToEmailHead;
8750
8773
  function isAlphanumeric(char) {
8751
8774
  if (char < '0' || '\x7F' < char) return false;
8752
8775
  return '0' <= char && char <= '9' || 'A' <= char && char <= 'Z' || 'a' <= char && char <= 'z';
@@ -8842,12 +8865,11 @@ function seek(source, position, state) {
8842
8865
  Object.defineProperty(exports, "__esModule", ({
8843
8866
  value: true
8844
8867
  }));
8845
- exports.unescsource = exports.delimiter = void 0;
8868
+ exports.unescsource = void 0;
8846
8869
  const parser_1 = __webpack_require__(605);
8847
8870
  const combinator_1 = __webpack_require__(3484);
8848
8871
  const text_1 = __webpack_require__(5655);
8849
8872
  const dom_1 = __webpack_require__(394);
8850
- exports.delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
8851
8873
  const unescsource = context => {
8852
8874
  const {
8853
8875
  source,
@@ -8871,7 +8893,7 @@ const unescsource = context => {
8871
8893
  default:
8872
8894
  if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
8873
8895
  text_1.nonWhitespace.lastIndex = position + 1;
8874
- let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length : (0, text_1.next)(source, position, state, exports.delimiter);
8896
+ let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length : next(source, position, state);
8875
8897
  i -= position;
8876
8898
  (0, combinator_1.consume)(i - 1, context);
8877
8899
  context.position += i - 1;
@@ -8879,6 +8901,79 @@ const unescsource = context => {
8879
8901
  }
8880
8902
  };
8881
8903
  exports.unescsource = unescsource;
8904
+ function next(source, position, state) {
8905
+ let index = seek(source, position, state);
8906
+ if (index === source.length) return source.length;
8907
+ const char = source[index];
8908
+ switch (char) {
8909
+ case ':':
8910
+ index = source.startsWith('//', index + 1) ? (0, text_1.backToUrlHead)(source, position, index) : index;
8911
+ break;
8912
+ case '@':
8913
+ index = ~state & 1 /* State.autolink */ ? (0, text_1.backToEmailHead)(source, position, index) : index;
8914
+ break;
8915
+ }
8916
+ return index;
8917
+ }
8918
+ function seek(source, position, state) {
8919
+ const cat = category(source[position]);
8920
+ for (let i = position + 1; i < source.length; ++i) {
8921
+ const char = source[i];
8922
+ switch (char) {
8923
+ case '\\':
8924
+ case '!':
8925
+ case '$':
8926
+ case '"':
8927
+ case '`':
8928
+ case '[':
8929
+ case ']':
8930
+ case '(':
8931
+ case ')':
8932
+ case '{':
8933
+ case '}':
8934
+ case '<':
8935
+ case '>':
8936
+ case '(':
8937
+ case ')':
8938
+ case '[':
8939
+ case ']':
8940
+ case '{':
8941
+ case '}':
8942
+ case '-':
8943
+ case '+':
8944
+ case '*':
8945
+ case '=':
8946
+ case '~':
8947
+ case '^':
8948
+ case '_':
8949
+ case ',':
8950
+ case '.':
8951
+ case ';':
8952
+ case ':':
8953
+ case '!':
8954
+ case '?':
8955
+ case '/':
8956
+ case '|':
8957
+ case '\r':
8958
+ case '\n':
8959
+ return i;
8960
+ case '@':
8961
+ case '#':
8962
+ if (~state & 1 /* State.autolink */) return i;
8963
+ continue;
8964
+ case ':':
8965
+ if (source[i + 1] === '/' && source[i + 2] === '/') return i;
8966
+ continue;
8967
+ default:
8968
+ if (cat && !category(char)) return i;
8969
+ continue;
8970
+ }
8971
+ }
8972
+ return source.length;
8973
+ }
8974
+ function category(char) {
8975
+ return '\x21' <= char && char <= '\x7E';
8976
+ }
8882
8977
 
8883
8978
  /***/ },
8884
8979
 
@@ -8962,9 +9057,9 @@ const combinator_1 = __webpack_require__(3484);
8962
9057
  const normalize_1 = __webpack_require__(4490);
8963
9058
  var blank;
8964
9059
  (function (blank) {
8965
- blank.line = new RegExp(/((?:^|\n)[^\S\r\n]*(?=\S))((?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)+(?=$|\r?\n))/g.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`).replace('IBC', `${normalize_1.invisibleBlankCharacters.join('')}`), 'g');
8966
- blank.start = new RegExp(/(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)+/y.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`).replace('IBC', `${normalize_1.invisibleBlankCharacters.join('')}`), 'y');
8967
- blank.unit = new RegExp(/(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)/y.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`).replace('IBC', `${normalize_1.invisibleBlankCharacters.join('')}`), 'y');
9060
+ blank.line = new RegExp(/((?:^|\n)[^\S\r\n]*(?=\S))((?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)+(?=$|\r?\n))/g.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`), 'g');
9061
+ blank.start = new RegExp(/(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)+/y.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`), 'y');
9062
+ blank.unit = new RegExp(/(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)/y.source.replace('IBHN', `(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')})`), 'y');
8968
9063
  })(blank || (blank = {}));
8969
9064
  function visualize(parser) {
8970
9065
  return (0, combinator_1.convert)(source => source.replace(blank.line, `$1${"\u001B" /* Command.Escape */}$2`), parser);
@@ -8976,15 +9071,15 @@ function blankWith(starts, delimiter) {
8976
9071
  return new RegExp([
8977
9072
  // 空行除去
8978
9073
  // 完全な空行はエスケープ済みなので再帰的バックトラックにはならない。
8979
- String.raw`(?:${starts}(?:\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|[${normalize_1.invisibleBlankCharacters.join('')}]|<wbr ?>)*)?`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
9074
+ String.raw`(?:${starts}(?:\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)*)?`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
8980
9075
  }
8981
9076
  exports.blankWith = blankWith;
8982
9077
  function beforeNonblankWith(delimiter) {
8983
- return new RegExp([typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source, String.raw`(?!\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|[${normalize_1.invisibleBlankCharacters.join('')}]|<wbr ?>)`].join(''), 'y');
9078
+ return new RegExp([typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source, String.raw`(?!\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`].join(''), 'y');
8984
9079
  }
8985
9080
  exports.beforeNonblankWith = beforeNonblankWith;
8986
9081
  function afterNonblankWith(delimiter) {
8987
- return new RegExp([String.raw`(?<!\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|[${normalize_1.invisibleBlankCharacters.join('')}]|<wbr ?>)`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
9082
+ return new RegExp([String.raw`(?<!\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
8988
9083
  }
8989
9084
  function isNonblankFirstLine(nodes) {
8990
9085
  if (nodes.length === 0) return true;
package/markdown.d.ts CHANGED
@@ -1082,7 +1082,7 @@ export namespace MarkdownParser {
1082
1082
  Inline<'url'>,
1083
1083
  Parser<string | HTMLElement, Context, [
1084
1084
  Parser<HTMLAnchorElement, Context, []>,
1085
- InlineParser,
1085
+ Parser<string, Context, []>,
1086
1086
  ]> {
1087
1087
  }
1088
1088
  export namespace UrlParser {
@@ -1092,7 +1092,7 @@ export namespace MarkdownParser {
1092
1092
  SourceParser.StrParser,
1093
1093
  Parser<string | HTMLElement, Context, [
1094
1094
  Parser<HTMLAnchorElement, Context, []>,
1095
- SourceParser.StrParser,
1095
+ Parser<string, Context, []>,
1096
1096
  ]>,
1097
1097
  ]> {
1098
1098
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.299.0",
3
+ "version": "0.299.2",
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",
@@ -37,6 +37,8 @@ export class Delimiters {
37
37
  assert(pattern !== '');
38
38
  return index(`'${pattern}`);
39
39
  case 'object':
40
+ assert(pattern.flags.includes('y'));
41
+ assert(/^yu?$/.test(pattern.flags));
40
42
  return index(`/${pattern.source}`);
41
43
  }
42
44
  }
@@ -4,24 +4,31 @@ import { Delimiters } from '../delimiter';
4
4
  type DelimiterOption = readonly [delimiter: string | RegExp, precedence: number];
5
5
 
6
6
  export function some<P extends Parser>(parser: P, limit?: number): P;
7
- export function some<P extends Parser>(parser: P, delimiters?: readonly DelimiterOption[]): P;
8
- export function some<P extends Parser>(parser: P, delimiter: string | RegExp, delimiters?: readonly DelimiterOption[]): P;
9
- export function some<P extends Parser>(parser: P, delimiter: string | RegExp, after: string | RegExp, delimiters?: readonly DelimiterOption[]): P;
10
- export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp | readonly DelimiterOption[], after?: string | RegExp | readonly DelimiterOption[], delimiters?: readonly DelimiterOption[], limit = -1): Parser<N> {
7
+ export function some<P extends Parser>(parser: P, delimiters?: readonly DelimiterOption[], limit?: number): P;
8
+ export function some<P extends Parser>(parser: P, delimiter: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
9
+ export function some<P extends Parser>(parser: P, delimiter: string | RegExp, after: string | RegExp, delimiters?: readonly DelimiterOption[], limit?: number): P;
10
+ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp | readonly DelimiterOption[], after?: number | string | RegExp | readonly DelimiterOption[], delimiters?: number | readonly DelimiterOption[], limit = 0): Parser<N> {
11
11
  if (typeof delimiter === 'number') {
12
12
  limit = delimiter;
13
+ delimiters = undefined;
13
14
  delimiter = undefined;
14
15
  }
15
16
  else if (Array.isArray(delimiter)) {
17
+ limit = after as number;
16
18
  delimiters = delimiter;
17
19
  delimiter = undefined;
18
20
  }
19
21
  else if (after === undefined || Array.isArray(after)) {
22
+ limit = delimiters as number;
20
23
  delimiters = after;
21
24
  after = undefined;
22
25
  }
26
+ else {
27
+ delimiters = delimiters as readonly DelimiterOption[];
28
+ }
23
29
  assert(parser);
24
30
  assert(delimiter !== '');
31
+ assert(delimiters === undefined || Array.isArray(delimiters));
25
32
  const match = Delimiters.tester(delimiter as string, after as string);
26
33
  const delims = delimiters?.map(([delimiter, precedence]) => ({
27
34
  signature: Delimiters.signature(delimiter),
@@ -43,7 +50,8 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
43
50
  if (result === undefined) break;
44
51
  if (context.position === pos) break;
45
52
  nodes = nodes?.import(result) ?? result;
46
- if (limit >= 0 && context.position - position > limit) break;
53
+ // 次にパースに成功すれば確実に制限値を超えるので制限値ちょうどでも中止する
54
+ if (limit > 0 && context.position - position >= limit) break;
47
55
  }
48
56
  delims && context.delimiters.pop(delims.length);
49
57
  assert(context.position >= position);
@@ -8,7 +8,11 @@ export function header(source: string): string {
8
8
 
9
9
  export function headers(source: string): string[] {
10
10
  const [el] = parse(source);
11
- return el?.textContent!.trimEnd().slice(el.firstChild!.firstChild!.textContent!.length).split(/\r?\n/) ?? [];
11
+ const acc = [];
12
+ for (let field = el?.firstChild?.firstChild; field = field?.nextSibling;) {
13
+ acc.push(field.textContent!);
14
+ }
15
+ return acc;
12
16
  }
13
17
 
14
18
  function parse(source: string): [HTMLElement, number] | [] {
@@ -65,8 +65,7 @@ const parser = (el => (entity: string): string => {
65
65
  })(html('span'));
66
66
  export const invisibleBlankHTMLEntityNames: readonly string[] = invisibleHTMLEntityNames
67
67
  .filter(name => parser(`&${name};`).trimStart() === '');
68
- export const invisibleBlankCharacters: readonly string[] = invisibleBlankHTMLEntityNames
69
- .map(name => parser(`&${name};`));
68
+ assert(invisibleBlankHTMLEntityNames.every(name => /^\s$/.test(parser(`&${name};`))));
70
69
  export const invisibleGraphHTMLEntityNames: readonly string[] = invisibleHTMLEntityNames
71
70
  .filter(name => parser(`&${name};`).trimStart() !== '');
72
71
  const unreadableEscapeHTMLEntityNames = invisibleHTMLEntityNames.filter(name => ![
@@ -125,7 +125,7 @@ describe('Unit: parser/api/parse', () => {
125
125
  '!{../../a}',
126
126
  ].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => el.outerHTML),
127
127
  [
128
- '<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span>\n</span></details></aside>',
128
+ '<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span></div></details></aside>',
129
129
  '<p><a class="account" href="https://source/@a" target="_blank">@a</a></p>',
130
130
  '<p><a class="account" href="https://domain/@a" target="_blank">@domain/a</a></p>',
131
131
  '<p><a class="channel" href="https://source/@a?ch=b" target="_blank">@a#b</a></p>',
@@ -158,7 +158,7 @@ describe('Unit: parser/api/parse', () => {
158
158
  '{./a}',
159
159
  ].join('\n\n'), { host: new URL(`${location.origin}/index.md`) }).children].map(el => el.outerHTML),
160
160
  [
161
- '<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span>\n</span></details></aside>',
161
+ '<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://source/x/y"><span class="field-name">URL</span>: <span class="field-value">https://source/x/y</span></div></details></aside>',
162
162
  '<p><a class="url" href="/a">^/a</a></p>',
163
163
  '<p><a class="url" href="https://source/x/a" target="_blank">./a</a></p>',
164
164
  ]);
@@ -173,7 +173,7 @@ describe('Unit: parser/api/parse', () => {
173
173
  '{./a}',
174
174
  ].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => el.outerHTML),
175
175
  [
176
- `<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="url" data-value="${location.origin}/x/y"><span class="field-name">URL</span>: <span class="field-value">${location.origin}/x/y</span>\n</span></details></aside>`,
176
+ `<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="${location.origin}/x/y"><span class="field-name">URL</span>: <span class="field-value">${location.origin}/x/y</span></div></details></aside>`,
177
177
  '<p><a class="url" href="/z/a">^/a</a></p>',
178
178
  '<p><a class="url" href="/x/a">./a</a></p>',
179
179
  ]);
@@ -204,9 +204,9 @@ describe('Unit: parser/api/parse', () => {
204
204
  '{#}',
205
205
  ].join('\n\n'), { host: new URL(`${location.origin}/z`) }).children].map(el => normalize(el.outerHTML)),
206
206
  [
207
- `<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="url" data-value="https://example/x"><span class="field-name">URL</span>: <span class="field-value">https://example/x</span>\n</span></details></aside>`,
207
+ `<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://example/x"><span class="field-name">URL</span>: <span class="field-value">https://example/x</span></div></details></aside>`,
208
208
  '<pre class="invalid" translate="no">---\nURL: https://example/y\n---\n</pre>',
209
- '<aside class="example" data-type="markdown"><pre translate="no">---\nURL: https://example/y\n---\n\n{#}</pre><hr><section><aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="url" data-value="https://example/y"><span class="field-name">URL</span>: <span class="field-value">https://example/y</span>\n</span></details></aside><p><a class="url" href="https://example/y#" target="_blank">#</a></p><h2>References</h2><ol class="references"></ol></section></aside>',
209
+ '<aside class="example" data-type="markdown"><pre translate="no">---\nURL: https://example/y\n---\n\n{#}</pre><hr><section><aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="url" data-value="https://example/y"><span class="field-name">URL</span>: <span class="field-value">https://example/y</span></div></details></aside><p><a class="url" href="https://example/y#" target="_blank">#</a></p><h2>References</h2><ol class="references"></ol></section></aside>',
210
210
  '<p><a class="url" href="https://example/x#" target="_blank">#</a></p>',
211
211
  ]);
212
212
  });
@@ -380,28 +380,28 @@ describe('Unit: parser/api/parse', () => {
380
380
  // 最悪計算量での実行速度はCommonMarkの公式JS実装の32nに対して1-4倍程度。
381
381
  // 5n = reference + link + url/math + ruby + text
382
382
  assert.deepStrictEqual(
383
- [...parse(`((([[[[#$[${'.'.repeat(19998)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
383
+ [...parse(`((([[[[#$http://[${'.'.repeat(19992)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
384
384
  .map(el => el.tagName),
385
385
  ['P']);
386
386
  });
387
387
 
388
388
  it('backtrack 1 error', () => {
389
389
  assert.deepStrictEqual(
390
- [...parse(`((([[[[#$[${'.'.repeat(19998 + 1)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
390
+ [...parse(`((([[[[#$http://[${'.'.repeat(19992 + 1)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
391
391
  .map(el => el.tagName),
392
392
  ['H1', 'PRE']);
393
393
  });
394
394
 
395
395
  it('backtrack 2', () => {
396
396
  assert.deepStrictEqual(
397
- [...parse(`((([[[[#$[${'.'.repeat(19998)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
397
+ [...parse(`((([[[[#$http://[${'.'.repeat(33324)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
398
398
  .map(el => el.tagName),
399
399
  ['P', 'OL']);
400
400
  });
401
401
 
402
402
  it('backtrack 2 error', () => {
403
403
  assert.deepStrictEqual(
404
- [...parse(`((([[[[#$[${'.'.repeat(19998 + 1)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
404
+ [...parse(`((([[[[#$http://[${'.'.repeat(33324 + 1)}]]]`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
405
405
  .map(el => el.tagName),
406
406
  ['H1', 'PRE']);
407
407
  });
@@ -22,7 +22,7 @@ export class Context extends Ctx {
22
22
  } = options;
23
23
  this.resources ??= {
24
24
  // バックトラックのせいで文字数制限を受けないようにする。
25
- clock: MAX_SEGMENT_SIZE * (6 + 1),
25
+ clock: MAX_SEGMENT_SIZE * (5 + 1),
26
26
  recursions: [
27
27
  5 || Recursion.block,
28
28
  20 || Recursion.blockquote,
@@ -24,11 +24,11 @@ describe('Unit: parser/header', () => {
24
24
  });
25
25
 
26
26
  it('basic', () => {
27
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
28
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
29
- assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span><span class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span>\n</span></details></aside>'], '']);
30
- assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span><span class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span>\n</span></details></aside>'], '']);
31
- assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
27
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
28
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
29
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
30
+ assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
31
+ assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
32
32
  });
33
33
 
34
34
  });
@@ -11,7 +11,7 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
11
11
  block(
12
12
  union([
13
13
  validate(context => context.header,
14
- focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,100}\1[^\S\r\n]*(?:$|\r?\n)/yi,
14
+ focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi,
15
15
  convert(source =>
16
16
  source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')),
17
17
  fmap(
@@ -42,11 +42,10 @@ const field: MarkdownParser.HeaderParser.FieldParser = line(({ source, position
42
42
  const name = source.slice(position, source.indexOf(':', position));
43
43
  const value = source.slice(position + name.length + 1).trim();
44
44
  return new List([
45
- new Node(html('span', { class: 'field', 'data-name': name.toLowerCase(), 'data-value': value }, [
45
+ new Node(html('div', { class: 'field', 'data-name': name.toLowerCase(), 'data-value': value }, [
46
46
  html('span', { class: 'field-name' }, name),
47
47
  ': ',
48
48
  html('span', { class: 'field-value' }, value),
49
- '\n',
50
49
  ])),
51
50
  ]);
52
51
  });
@@ -41,17 +41,22 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
41
41
  new Node(html('span', { class: bracketname(context, 1, 1) }, defrag(unwrap(nodes))))
42
42
  ]);
43
43
  }
44
- recursion.add(MAX_DEPTH - (resources?.recursions[Recursion.bracket] ?? resources?.recursions.at(-1) ?? MAX_DEPTH));
44
+ recursion.add(
45
+ MAX_DEPTH - (resources?.recursions[Recursion.bracket] ?? resources?.recursions.at(-1) ?? MAX_DEPTH));
45
46
  context.position += 1;
46
47
  return new List([
47
- new Node(html('sup', { class: 'annotation' }, [html('span', defrag(unwrap(trimBlankNodeEnd(nodes))))]))
48
+ new Node(html('sup', { class: 'annotation' }, [
49
+ html('span', defrag(unwrap(trimBlankNodeEnd(nodes))))
50
+ ]))
48
51
  ]);
49
52
  },
50
53
  (nodes, context, prefix, postfix) => {
51
54
  assert(postfix === 0);
52
55
  for (let i = 0; i < prefix; ++i) {
53
56
  nodes.unshift(new Node('('));
54
- nodes = new List([new Node(html('span', { class: bracketname(context, 0, 0) }, defrag(unwrap(nodes))))]);
57
+ nodes = new List([
58
+ new Node(html('span', { class: bracketname(context, 0, 0) }, defrag(unwrap(nodes))))
59
+ ]);
55
60
  context.range += 1;
56
61
  }
57
62
  return nodes;
@@ -2,13 +2,12 @@ import { AutolinkParser } from '../../inline';
2
2
  import { State, Recursion, Backtrack } from '../../context';
3
3
  import { List, Node } from '../../../combinator/data/parser';
4
4
  import { union, tails, some, recursion, precedence, state, constraint, focus, rewrite, surround, open, lazy } from '../../../combinator';
5
- import { inline } from '../../inline';
6
5
  import { parse } from '../link';
7
6
  import { unescsource, str } from '../../source';
8
7
 
9
8
  export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
10
9
  open(
11
- /(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[\x21-\x7E])/y,
10
+ /(?<![0-9A-Za-z][.+-]?|[@#])https?:\/\/(?=[[0-9A-Za-z])/y,
12
11
  precedence(0, some(union([
13
12
  some(unescsource, /(?<![-+*=~^_,.;:!?]|\/{3})(?:[-+*=~^_,.;:!?]|\/{3,}(?!\/))*(?=[\\$"`\[\](){}<>()[]{}|]|[^\x21-\x7E]|$)/y),
14
13
  precedence(1, bracket),
@@ -18,7 +17,7 @@ export const url: AutolinkParser.UrlParser = lazy(() => rewrite(
18
17
  union([
19
18
  constraint(State.autolink, state(State.autolink, context =>
20
19
  new List([new Node(parse(new List(), new List([new Node(context.source)]), context))]))),
21
- open(str(/[^:]+/y), some(inline)),
20
+ context => new List([new Node(context.source)]),
22
21
  ])));
23
22
 
24
23
  export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
@@ -36,7 +35,7 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
36
35
  context))
37
36
  ]);
38
37
  })),
39
- str(/[^:]+/y),
38
+ context => new List([new Node(context.source)]),
40
39
  ]),
41
40
  ])));
42
41
 
@@ -93,8 +93,8 @@ describe('Unit: parser/inline/math', () => {
93
93
  assert.deepStrictEqual(inspect(parser, input('$\\Begin$', new Context())), [['<span class="invalid" translate="no">$\\Begin$</span>'], '']);
94
94
  assert.deepStrictEqual(inspect(parser, input('$\\begin{}$', new Context())), [['<span class="invalid" translate="no">$\\begin{}$</span>'], '']);
95
95
  assert.deepStrictEqual(inspect(parser, input('${\\begin}$', new Context())), [['<span class="invalid" translate="no">${\\begin}$</span>'], '']);
96
- assert.deepStrictEqual(inspect(parser, input('$http://host$', new Context())), [['<span class="invalid" translate="no">$http://host$</span>'], '']);
97
- assert.deepStrictEqual(inspect(parser, input('${http://host}$', new Context())), [['<span class="invalid" translate="no">${http://host}$</span>'], '']);
96
+ assert.deepStrictEqual(inspect(parser, input('$http://host$', new Context())), undefined);
97
+ assert.deepStrictEqual(inspect(parser, input('${http://host}$', new Context())), undefined);
98
98
  assert.deepStrictEqual(inspect(parser, input(' ${a}$', new Context())), undefined);
99
99
  });
100
100
 
@@ -6,7 +6,7 @@ import { escsource, str } from '../source';
6
6
  import { invalid } from '../util';
7
7
  import { html } from 'typed-dom/dom';
8
8
 
9
- const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])|:\/\//i;
9
+ const forbiddenCommand = /\\(?:begin|tiny|huge|large)(?![a-z])/i;
10
10
 
11
11
  export const math: MathParser = lazy(() => rewrite(
12
12
  union([
@@ -19,7 +19,7 @@ export const math: MathParser = lazy(() => rewrite(
19
19
  surround(
20
20
  /\$(?![\s{}])/y,
21
21
  precedence(2, some(union([
22
- some(escsource, /\$|[`"{}\r\n]/y),
22
+ some(escsource, /[`"{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y),
23
23
  precedence(4, bracket),
24
24
  ]))),
25
25
  /(?<!\s)\$(?![-0-9A-Za-z])/y,
@@ -45,7 +45,7 @@ const bracket: MathParser.BracketParser = lazy(() => surround(
45
45
  recursion(Recursion.terminal,
46
46
  some(union([
47
47
  bracket,
48
- some(escsource, /[{}$\r\n]/y),
48
+ some(escsource, /[{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y),
49
49
  ]))),
50
50
  str('}'),
51
51
  true));
@@ -20,13 +20,12 @@ export const ruby: RubyParser = lazy(() => bind(
20
20
  })),
21
21
  dup(surround(
22
22
  '(', text, ')',
23
- false,
24
- [3 | Backtrack.ruby])),
23
+ false)),
25
24
  ]),
26
25
  ([{ value: texts }, { value: rubies = undefined } = {}], context) => {
27
26
  if (rubies === undefined) {
28
27
  const head = context.position - context.range;
29
- return void setBacktrack(context, 2 | Backtrack.ruby, head);
28
+ return void setBacktrack(context, 2 | Backtrack.link | Backtrack.ruby, head);
30
29
  }
31
30
  switch (true) {
32
31
  case texts.length >= rubies.length:
@@ -167,7 +167,7 @@ describe('Unit: parser/inline', () => {
167
167
  assert.deepStrictEqual(inspect(parser, input('"[% "*"* %]', new Context())), [['"', '<span class="remark"><input type="checkbox"><span>[% "*"* %]</span></span>'], '']);
168
168
  assert.deepStrictEqual(inspect(parser, input('"{{""}}', new Context())), [['"', '{', '<a class="url" href="&quot;&quot;">""</a>', '}'], '']);
169
169
  assert.deepStrictEqual(inspect(parser, input('[#http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::http://host/(&lt;bdi&gt;)">http://host/<span class="paren">(<span class="invalid">&lt;bdi&gt;</span>)</span></a>', '</bdi', '>'], '']);
170
- assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(&lt;bdi&gt;)">@a/http://host/<span class="paren">(<span class="invalid">&lt;bdi&gt;</span>)</span></a>', '</bdi', '>'], '']);
170
+ assert.deepStrictEqual(inspect(parser, input('[#@a/http://host/(<bdi>)]</bdi>', new Context())), [['<a class="index" href="#index::@a/http://host/(&lt;bdi&gt;)">@a/http://host/(&lt;bdi&gt;)</a>', '</bdi', '>'], '']);
171
171
  assert.deepStrictEqual(inspect(parser, input('[#a|<bdi>]</bdi>', new Context())), [['<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
172
172
  assert.deepStrictEqual(inspect(parser, input('[[#a|<bdi>]</bdi>', new Context())), [['[', '<a class="index" href="#index::a|&lt;bdi&gt;">a|<span class="invalid">&lt;bdi&gt;</span></a>', '</bdi', '>'], '']);
173
173
  assert.deepStrictEqual(inspect(parser, input('[*==*]{a}', new Context())), [['<a class="link" href="a">*==*</a>'], '']);
@@ -68,10 +68,10 @@ export function repeat<N extends HTMLElement | string>(
68
68
  follow = follow > 0 ? follow : countFollows(source, pos, closer, lead / opener.length | 0);
69
69
  nodes = cons(nodes, context, lead, follow);
70
70
  if (context.position > pos) {
71
- const advance = opener.length * (context.position - pos) / closer.length | 0;
71
+ const advance = context.position - pos;
72
72
  i -= advance;
73
73
  follow -= advance;
74
- depth -= advance;
74
+ depth -= advance / closer.length | 0;
75
75
  }
76
76
  continue;
77
77
  }
@@ -100,10 +100,10 @@ export function repeat<N extends HTMLElement | string>(
100
100
  nodes = cons(nodes, context, lead, follow);
101
101
  state = true;
102
102
  if (context.position > pos) {
103
- const advance = opener.length * (context.position - pos) / closer.length | 0;
103
+ const advance = context.position - pos;
104
104
  i -= advance;
105
105
  follow -= advance;
106
- depth -= advance;
106
+ depth -= advance / closer.length | 0;
107
107
  }
108
108
  continue;
109
109
  }
@@ -3,13 +3,10 @@ import { Command } from '../context';
3
3
  import { Flag } from '../node';
4
4
  import { List, Node } from '../../combinator/data/parser';
5
5
  import { consume } from '../../combinator';
6
- import { next } from './text';
7
6
  import { html } from 'typed-dom/dom';
8
7
 
9
- const delimiter = /(?=[\\$"`\[\](){}\r\n]|\s\$|:\/\/)/g;
10
-
11
8
  export const escsource: EscapableSourceParser = context => {
12
- const { source, position, state } = context;
9
+ const { source, position } = context;
13
10
  if (position === source.length) return;
14
11
  const char = source[position];
15
12
  consume(1, context);
@@ -38,7 +35,7 @@ export const escsource: EscapableSourceParser = context => {
38
35
  default:
39
36
  assert(char !== '\n');
40
37
  if (context.sequential) return new List([new Node(char)]);
41
- let i = next(source, position, state, delimiter);
38
+ let i = seek(source, position);
42
39
  assert(i > position);
43
40
  i -= position;
44
41
  consume(i - 1, context);
@@ -46,3 +43,29 @@ export const escsource: EscapableSourceParser = context => {
46
43
  return new List([new Node(source.slice(position, context.position))]);
47
44
  }
48
45
  };
46
+
47
+ function seek(source: string, position: number): number {
48
+ for (let i = position + 1; i < source.length; ++i) {
49
+ const char = source[i];
50
+ switch (char) {
51
+ case '\\':
52
+ case '$':
53
+ case '"':
54
+ case '`':
55
+ case ':':
56
+ case '[':
57
+ case ']':
58
+ case '(':
59
+ case ')':
60
+ case '{':
61
+ case '}':
62
+ case '\r':
63
+ case '\n':
64
+ return i;
65
+ default:
66
+ continue;
67
+ }
68
+ assert(false);
69
+ }
70
+ return source.length;
71
+ }
@@ -83,28 +83,20 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
83
83
  }
84
84
  }
85
85
 
86
- export function next(source: string, position: number, state: number, delimiter?: RegExp): number {
87
- let index: number;
88
- if (delimiter) {
89
- delimiter.lastIndex = position + 1;
90
- delimiter.test(source);
91
- index = delimiter.lastIndex || position;
92
- }
93
- else {
94
- index = seek(source, position, state);
95
- }
96
- if (index === position || index === source.length) return source.length;
86
+ function next(source: string, position: number, state: number): number {
87
+ let index= seek(source, position, state);
97
88
  assert(index > position);
89
+ if (index === source.length) return source.length;
98
90
  const char = source[index];
99
91
  switch (char) {
100
92
  case '%':
101
- assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true) || delimiter);
102
- index += !delimiter && index - 1 > position
93
+ assert(source.startsWith('%]', index) && isWhitespace(source[index - 1], true));
94
+ index += index - 1 > position
103
95
  ? -1
104
96
  : 0;
105
97
  break;
106
98
  case '[':
107
- index += !delimiter && index - 1 > position && source.startsWith(' [|', index - 1)
99
+ index += index - 1 > position && source.startsWith(' [|', index - 1)
108
100
  ? -1
109
101
  : 0;
110
102
  break;
@@ -122,7 +114,7 @@ export function next(source: string, position: number, state: number, delimiter?
122
114
  assert(index > position);
123
115
  return index;
124
116
  }
125
- function backToUrlHead(source: string, position: number, index: number): number {
117
+ export function backToUrlHead(source: string, position: number, index: number): number {
126
118
  const delim = index;
127
119
  let state = false;
128
120
  for (let i = index - 1; i >= position; --i) {
@@ -145,7 +137,7 @@ function backToUrlHead(source: string, position: number, index: number): number
145
137
  ? delim
146
138
  : index;
147
139
  }
148
- function backToEmailHead(source: string, position: number, index: number): number {
140
+ export function backToEmailHead(source: string, position: number, index: number): number {
149
141
  const delim = index;
150
142
  let state = false;
151
143
  for (let i = index - 1; i >= position; --i) {
@@ -15,7 +15,7 @@ describe('Unit: parser/source/unescapable', () => {
15
15
  it('basic', () => {
16
16
  assert.deepStrictEqual(inspect(parser, input('a', new Context())), [['a'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('ab', new Context())), [['ab'], '']);
18
- assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b', ' c'], '']);
18
+ assert.deepStrictEqual(inspect(parser, input('a b c', new Context())), [['a', ' b c'], '']);
19
19
  assert.deepStrictEqual(inspect(parser, input('09あいAZaz', new Context())), [['09', 'あいAZaz'], '']);
20
20
  });
21
21
 
@@ -1,13 +1,11 @@
1
1
  import { UnescapableSourceParser } from '../source';
2
- import { Command } from '../context';
2
+ import { State, Command } from '../context';
3
3
  import { Flag } from '../node';
4
4
  import { List, Node } from '../../combinator/data/parser';
5
5
  import { consume } from '../../combinator';
6
- import { nonWhitespace, canSkip, next } from './text';
6
+ import { nonWhitespace, canSkip, backToUrlHead, backToEmailHead } from './text';
7
7
  import { html } from 'typed-dom/dom';
8
8
 
9
- export const delimiter = /(?=(?=[\x00-\x7F])[^0-9A-Za-z]|(?<=[\x00-\x7F])[^\x00-\x7F])/g;
10
-
11
9
  export const unescsource: UnescapableSourceParser = context => {
12
10
  const { source, position, state } = context;
13
11
  if (position === source.length) return;
@@ -32,7 +30,7 @@ export const unescsource: UnescapableSourceParser = context => {
32
30
  ? nonWhitespace.test(source)
33
31
  ? nonWhitespace.lastIndex - 1
34
32
  : source.length
35
- : next(source, position, state, delimiter);
33
+ : next(source, position, state);
36
34
  assert(i > position);
37
35
  i -= position;
38
36
  consume(i - 1, context);
@@ -40,3 +38,86 @@ export const unescsource: UnescapableSourceParser = context => {
40
38
  return new List([new Node(source.slice(position, context.position))]);
41
39
  }
42
40
  };
41
+
42
+ function next(source: string, position: number, state: number): number {
43
+ let index= seek(source, position, state);
44
+ assert(index > position);
45
+ if (index === source.length) return source.length;
46
+ const char = source[index];
47
+ switch (char) {
48
+ case ':':
49
+ index = source.startsWith('//', index + 1)
50
+ ? backToUrlHead(source, position, index)
51
+ : index;
52
+ break;
53
+ case '@':
54
+ index = ~state & State.autolink
55
+ ? backToEmailHead(source, position, index)
56
+ : index;
57
+ break;
58
+ }
59
+ assert(index > position);
60
+ return index;
61
+ }
62
+
63
+ function seek(source: string, position: number, state: number): number {
64
+ const cat = category(source[position]);
65
+ for (let i = position + 1; i < source.length; ++i) {
66
+ const char = source[i];
67
+ switch (char) {
68
+ case '\\':
69
+ case '!':
70
+ case '$':
71
+ case '"':
72
+ case '`':
73
+ case '[':
74
+ case ']':
75
+ case '(':
76
+ case ')':
77
+ case '{':
78
+ case '}':
79
+ case '<':
80
+ case '>':
81
+ case '(':
82
+ case ')':
83
+ case '[':
84
+ case ']':
85
+ case '{':
86
+ case '}':
87
+ case '-':
88
+ case '+':
89
+ case '*':
90
+ case '=':
91
+ case '~':
92
+ case '^':
93
+ case '_':
94
+ case ',':
95
+ case '.':
96
+ case ';':
97
+ case ':':
98
+ case '!':
99
+ case '?':
100
+ case '/':
101
+ case '|':
102
+ case '\r':
103
+ case '\n':
104
+ return i;
105
+ case '@':
106
+ case '#':
107
+ if (~state & State.autolink) return i;
108
+ continue;
109
+ case ':':
110
+ if (source[i + 1] === '/' && source[i + 2] === '/') return i;
111
+ continue;
112
+ default:
113
+ if (cat && !category(char)) return i;
114
+ continue;
115
+ }
116
+ assert(false);
117
+ }
118
+ return source.length;
119
+ }
120
+
121
+ function category(char: string): boolean {
122
+ return '\x21' <= char && char <= '\x7E';
123
+ }
@@ -2,23 +2,20 @@ import { Parser, List, Node } from '../combinator/data/parser';
2
2
  import { Command } from './context';
3
3
  import { Flag } from './node';
4
4
  import { convert, fmap } from '../combinator';
5
- import { invisibleBlankHTMLEntityNames, invisibleBlankCharacters } from './api/normalize';
5
+ import { invisibleBlankHTMLEntityNames } from './api/normalize';
6
6
 
7
7
  namespace blank {
8
8
  export const line = new RegExp(
9
- /((?:^|\n)[^\S\r\n]*(?=\S))((?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)+(?=$|\r?\n))/g.source
10
- .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`)
11
- .replace('IBC', `${invisibleBlankCharacters.join('')}`),
9
+ /((?:^|\n)[^\S\r\n]*(?=\S))((?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)+(?=$|\r?\n))/g.source
10
+ .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`),
12
11
  'g');
13
12
  export const start = new RegExp(
14
- /(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)+/y.source
15
- .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`)
16
- .replace('IBC', `${invisibleBlankCharacters.join('')}`),
13
+ /(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)+/y.source
14
+ .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`),
17
15
  'y');
18
16
  export const unit = new RegExp(
19
- /(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|[IBC]|<wbr ?>)/y.source
20
- .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`)
21
- .replace('IBC', `${invisibleBlankCharacters.join('')}`),
17
+ /(?:[^\S\r\n]|\\(?=$|\s)|&IBHN;|<wbr ?>)/y.source
18
+ .replace('IBHN', `(?:${invisibleBlankHTMLEntityNames.join('|')})`),
22
19
  'y');
23
20
  }
24
21
 
@@ -34,7 +31,7 @@ export function blankWith(starts: '\n', delimiter: string | RegExp): RegExp {
34
31
  return new RegExp([
35
32
  // 空行除去
36
33
  // 完全な空行はエスケープ済みなので再帰的バックトラックにはならない。
37
- String.raw`(?:${starts}(?:\\?\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|[${invisibleBlankCharacters.join('')}]|<wbr ?>)*)?`,
34
+ String.raw`(?:${starts}(?:\\?\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)*)?`,
38
35
  typeof delimiter === 'string'
39
36
  ? delimiter.replace(/[*+()\[\]]/g, '\\$&')
40
37
  : delimiter.source,
@@ -45,12 +42,12 @@ export function beforeNonblankWith(delimiter: string | RegExp): RegExp {
45
42
  typeof delimiter === 'string'
46
43
  ? delimiter.replace(/[*+()\[\]]/g, '\\$&')
47
44
  : delimiter.source,
48
- String.raw`(?!\\?\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|[${invisibleBlankCharacters.join('')}]|<wbr ?>)`,
45
+ String.raw`(?!\\?\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`,
49
46
  ].join(''), 'y');
50
47
  }
51
48
  function afterNonblankWith(delimiter: string | RegExp): RegExp {
52
49
  return new RegExp([
53
- String.raw`(?<!\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|[${invisibleBlankCharacters.join('')}]|<wbr ?>)`,
50
+ String.raw`(?<!\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`,
54
51
  typeof delimiter === 'string'
55
52
  ? delimiter.replace(/[*+()\[\]]/g, '\\$&')
56
53
  : delimiter.source,