securemark 0.296.1 → 0.296.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,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.296.2
4
+
5
+ - Fix leading blank character validation with nested syntax.
6
+
3
7
  ## 0.296.1
4
8
 
5
9
  - Fix parsers to disallow leading blank characters.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.296.1 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.296.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"));
@@ -2603,18 +2603,19 @@ Object.defineProperty(exports, "__esModule", ({
2603
2603
  value: true
2604
2604
  }));
2605
2605
  exports.verify = exports.validate = void 0;
2606
- const combinator_1 = __webpack_require__(3484);
2606
+ const delimiter_1 = __webpack_require__(385);
2607
+ const bind_1 = __webpack_require__(994);
2607
2608
  function validate(pattern, parser) {
2608
2609
  if (typeof pattern === 'function') return guard(pattern, parser);
2609
- const match = (0, combinator_1.matcher)(pattern, false);
2610
- return input => match(input) ? parser(input) : undefined;
2610
+ const test = (0, delimiter_1.tester)(pattern, false);
2611
+ return input => test(input) && parser(input);
2611
2612
  }
2612
2613
  exports.validate = validate;
2613
2614
  function guard(f, parser) {
2614
2615
  return input => f(input) ? parser(input) : undefined;
2615
2616
  }
2616
2617
  function verify(parser, cond) {
2617
- return (0, combinator_1.bind)(parser, (nodes, context) => cond(nodes, context) ? nodes : undefined);
2618
+ return (0, bind_1.bind)(parser, (nodes, context) => cond(nodes, context) ? nodes : undefined);
2618
2619
  }
2619
2620
  exports.verify = verify;
2620
2621
 
@@ -2989,9 +2990,9 @@ Object.defineProperty(exports, "__esModule", ({
2989
2990
  }));
2990
2991
  exports.rewrite = exports.focus = void 0;
2991
2992
  const parser_1 = __webpack_require__(605);
2992
- const combinator_1 = __webpack_require__(3484);
2993
+ const delimiter_1 = __webpack_require__(385);
2993
2994
  function focus(scope, parser, slice = true) {
2994
- const match = (0, combinator_1.matcher)(scope, false);
2995
+ const match = (0, delimiter_1.matcher)(scope, false);
2995
2996
  return (0, parser_1.failsafe)(arg => {
2996
2997
  const {
2997
2998
  context
@@ -3067,22 +3068,22 @@ Object.defineProperty(exports, "__esModule", ({
3067
3068
  }));
3068
3069
  exports.setBacktrack = exports.isBacktrack = exports.close = exports.open = exports.surround = void 0;
3069
3070
  const parser_1 = __webpack_require__(605);
3070
- const combinator_1 = __webpack_require__(3484);
3071
+ const delimiter_1 = __webpack_require__(385);
3071
3072
  function surround(opener, parser, closer, optional = false, backtracks = [], f, g) {
3072
3073
  switch (typeof opener) {
3073
3074
  case 'string':
3074
3075
  case 'object':
3075
- opener = (0, combinator_1.clear)((0, combinator_1.matcher)(opener, true));
3076
+ opener = (0, delimiter_1.tester)(opener, true);
3076
3077
  }
3077
3078
  switch (typeof parser) {
3078
3079
  case 'string':
3079
3080
  case 'object':
3080
- parser = (0, combinator_1.clear)((0, combinator_1.matcher)(parser, true));
3081
+ parser = (0, delimiter_1.tester)(parser, true);
3081
3082
  }
3082
3083
  switch (typeof closer) {
3083
3084
  case 'string':
3084
3085
  case 'object':
3085
- closer = (0, combinator_1.clear)((0, combinator_1.matcher)(closer, true));
3086
+ closer = (0, delimiter_1.tester)(closer, true);
3086
3087
  }
3087
3088
  const [blen, rbs, wbs] = reduce(backtracks);
3088
3089
  return (0, parser_1.failsafe)(input => {
@@ -3099,7 +3100,7 @@ function surround(opener, parser, closer, optional = false, backtracks = [], f,
3099
3100
  } = context;
3100
3101
  context.linebreak = 0;
3101
3102
  const nodesO = opener(input);
3102
- if (!nodesO) {
3103
+ if (nodesO === undefined) {
3103
3104
  return void revert(context, linebreak);
3104
3105
  }
3105
3106
  if (rbs && isBacktrack(context, rbs, position, blen)) {
@@ -3107,14 +3108,14 @@ function surround(opener, parser, closer, optional = false, backtracks = [], f,
3107
3108
  }
3108
3109
  const nodesM = context.position < source.length ? parser(input) : undefined;
3109
3110
  context.range = context.position - position;
3110
- if (!nodesM && !optional) {
3111
+ if (nodesM === undefined && !optional) {
3111
3112
  wbs && setBacktrack(context, wbs, position);
3112
3113
  const result = g?.([nodesO, nodesM], context);
3113
3114
  return result || void revert(context, linebreak);
3114
3115
  }
3115
3116
  const nodesC = nodesM || optional ? closer(input) : undefined;
3116
3117
  context.range = context.position - position;
3117
- if (!nodesC) {
3118
+ if (nodesC === undefined) {
3118
3119
  wbs && setBacktrack(context, wbs, position);
3119
3120
  const result = g?.([nodesO, nodesM], context);
3120
3121
  return result || void revert(context, linebreak);
@@ -3123,7 +3124,7 @@ function surround(opener, parser, closer, optional = false, backtracks = [], f,
3123
3124
  return void revert(context, linebreak);
3124
3125
  }
3125
3126
  context.range = context.position - position;
3126
- const result = f ? f([nodesO, nodesM, nodesC], context) : nodesO.import(nodesM ?? new parser_1.List()).import(nodesC);
3127
+ const result = f ? f([nodesO, nodesM, nodesC], context) : nodesM ? nodesO.import(nodesM).import(nodesC) : nodesO.import(nodesC);
3127
3128
  if (result) {
3128
3129
  context.linebreak ||= linebreak;
3129
3130
  }
@@ -3245,8 +3246,9 @@ exports.fmap = fmap;
3245
3246
  Object.defineProperty(exports, "__esModule", ({
3246
3247
  value: true
3247
3248
  }));
3248
- exports.Delimiters = void 0;
3249
- const combinator_1 = __webpack_require__(3484);
3249
+ exports.tester = exports.matcher = exports.Delimiters = void 0;
3250
+ const parser_1 = __webpack_require__(605);
3251
+ const context_1 = __webpack_require__(5745);
3250
3252
  class Delimiters {
3251
3253
  constructor() {
3252
3254
  this.tree = {};
@@ -3276,9 +3278,9 @@ class Delimiters {
3276
3278
  return () => undefined;
3277
3279
  case 'string':
3278
3280
  case 'object':
3279
- const match = (0, combinator_1.matcher)(pattern, false);
3280
- const verify = after ? (0, combinator_1.matcher)(after, false) : undefined;
3281
- return verify ? input => match(input) !== undefined && verify(input) !== undefined || undefined : input => match(input) !== undefined || undefined;
3281
+ const test = tester(pattern, false);
3282
+ const verify = after ? tester(after, false) : undefined;
3283
+ return verify ? input => test(input) !== undefined && verify(input) !== undefined || undefined : input => test(input) !== undefined || undefined;
3282
3284
  }
3283
3285
  }
3284
3286
  registry(signature) {
@@ -3390,6 +3392,90 @@ class Delimiters {
3390
3392
  }
3391
3393
  }
3392
3394
  exports.Delimiters = Delimiters;
3395
+ function matcher(pattern, advance, after) {
3396
+ const count = typeof pattern === 'object' ? /[^^\\*+][*+]/.test(pattern.source) : false;
3397
+ switch (typeof pattern) {
3398
+ case 'string':
3399
+ if (pattern === '') return () => new parser_1.List([new parser_1.Node(pattern)]);
3400
+ return input => {
3401
+ const {
3402
+ context
3403
+ } = input;
3404
+ const {
3405
+ source,
3406
+ position
3407
+ } = context;
3408
+ if (!source.startsWith(pattern, position)) return;
3409
+ if (advance) {
3410
+ context.position += pattern.length;
3411
+ }
3412
+ const next = after?.(input);
3413
+ return after ? next && new parser_1.List([new parser_1.Node(pattern)]).import(next) : new parser_1.List([new parser_1.Node(pattern)]);
3414
+ };
3415
+ case 'object':
3416
+ return input => {
3417
+ const {
3418
+ context
3419
+ } = input;
3420
+ const {
3421
+ source,
3422
+ position
3423
+ } = context;
3424
+ pattern.lastIndex = position;
3425
+ if (!pattern.test(source)) return;
3426
+ const src = source.slice(position, pattern.lastIndex);
3427
+ count && (0, context_1.consume)(src.length, context);
3428
+ if (advance) {
3429
+ context.position += src.length;
3430
+ }
3431
+ const next = after?.(input);
3432
+ return after ? next && new parser_1.List([new parser_1.Node(src)]).import(next) : new parser_1.List([new parser_1.Node(src)]);
3433
+ };
3434
+ }
3435
+ }
3436
+ exports.matcher = matcher;
3437
+ function tester(pattern, advance, after) {
3438
+ const count = typeof pattern === 'object' ? /[^^\\*+][*+]/.test(pattern.source) : false;
3439
+ switch (typeof pattern) {
3440
+ case 'string':
3441
+ if (pattern === '') return () => new parser_1.List();
3442
+ return input => {
3443
+ const {
3444
+ context
3445
+ } = input;
3446
+ const {
3447
+ source,
3448
+ position
3449
+ } = context;
3450
+ if (!source.startsWith(pattern, position)) return;
3451
+ if (advance) {
3452
+ context.position += pattern.length;
3453
+ }
3454
+ if (after && after(input) === undefined) return;
3455
+ return new parser_1.List();
3456
+ };
3457
+ case 'object':
3458
+ return input => {
3459
+ const {
3460
+ context
3461
+ } = input;
3462
+ const {
3463
+ source,
3464
+ position
3465
+ } = context;
3466
+ pattern.lastIndex = position;
3467
+ if (!pattern.test(source)) return;
3468
+ const len = pattern.lastIndex - position;
3469
+ count && (0, context_1.consume)(len, context);
3470
+ if (advance) {
3471
+ context.position += len;
3472
+ }
3473
+ if (after && after(input) === undefined) return;
3474
+ return new parser_1.List();
3475
+ };
3476
+ }
3477
+ }
3478
+ exports.tester = tester;
3393
3479
 
3394
3480
  /***/ },
3395
3481
 
@@ -3630,8 +3716,7 @@ exports.failsafe = failsafe;
3630
3716
  Object.defineProperty(exports, "__esModule", ({
3631
3717
  value: true
3632
3718
  }));
3633
- exports.matcher = exports.constraint = exports.state = exports.precedence = exports.recursion = exports.consume = exports.creation = exports.context = exports.reset = void 0;
3634
- const parser_1 = __webpack_require__(605);
3719
+ exports.constraint = exports.state = exports.precedence = exports.recursion = exports.consume = exports.creation = exports.context = exports.reset = void 0;
3635
3720
  const alias_1 = __webpack_require__(5413);
3636
3721
  const assign_1 = __webpack_require__(9888);
3637
3722
  function reset(base, parser) {
@@ -3790,45 +3875,6 @@ function constraint(state, positive, parser) {
3790
3875
  };
3791
3876
  }
3792
3877
  exports.constraint = constraint;
3793
- function matcher(pattern, advance, verify) {
3794
- const count = typeof pattern === 'object' ? /[^^\\*+][*+]/.test(pattern.source) : false;
3795
- switch (typeof pattern) {
3796
- case 'string':
3797
- return ({
3798
- context
3799
- }) => {
3800
- const {
3801
- source,
3802
- position
3803
- } = context;
3804
- if (!source.startsWith(pattern, position)) return;
3805
- if (verify?.(source, position, pattern.length) === false) return;
3806
- if (advance) {
3807
- context.position += pattern.length;
3808
- }
3809
- return new parser_1.List([new parser_1.Node(pattern)]);
3810
- };
3811
- case 'object':
3812
- return ({
3813
- context
3814
- }) => {
3815
- const {
3816
- source,
3817
- position
3818
- } = context;
3819
- pattern.lastIndex = position;
3820
- if (!pattern.test(source)) return;
3821
- const src = source.slice(position, pattern.lastIndex);
3822
- count && consume(src.length, context);
3823
- if (verify?.(source, position, src.length) === false) return;
3824
- if (advance) {
3825
- context.position += src.length;
3826
- }
3827
- return new parser_1.List([new parser_1.Node(src)]);
3828
- };
3829
- }
3830
- }
3831
- exports.matcher = matcher;
3832
3878
 
3833
3879
  /***/ },
3834
3880
 
@@ -6243,7 +6289,7 @@ const inline_1 = __webpack_require__(7973);
6243
6289
  const visibility_1 = __webpack_require__(6364);
6244
6290
  const util_1 = __webpack_require__(4992);
6245
6291
  const dom_1 = __webpack_require__(394);
6246
- exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, combinator_1.surround)('((', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]])))), '))', false, [2, 1 | 4 /* Backtrack.common */, 3 | 128 /* Backtrack.doublebracket */], ([, ns], context) => context.linebreak === 0 ? new parser_1.List([new parser_1.Node((0, dom_1.html)('sup', {
6292
+ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, combinator_1.surround)((0, combinator_1.close)('((', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]))), '))', false, [2, 1 | 4 /* Backtrack.common */, 3 | 128 /* Backtrack.doublebracket */], ([, ns], context) => context.linebreak === 0 ? new parser_1.List([new parser_1.Node((0, dom_1.html)('sup', {
6247
6293
  class: 'annotation'
6248
6294
  }, [(0, dom_1.html)('span', (0, dom_1.defrag)((0, util_1.unwrap)((0, visibility_1.trimBlankNodeEnd)(ns))))]))]) : undefined, (_, context) => {
6249
6295
  const {
@@ -6683,7 +6729,7 @@ const inline_1 = __webpack_require__(7973);
6683
6729
  const visibility_1 = __webpack_require__(6364);
6684
6730
  const util_1 = __webpack_require__(4992);
6685
6731
  const dom_1 = __webpack_require__(394);
6686
- exports.deletion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('~~', (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '~~')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '~'), true)])), '~~', false, [], ([, bs], {
6732
+ exports.deletion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('~~', '', (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '~~')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '~'), true)])), '~~', false, [], ([, bs], {
6687
6733
  buffer
6688
6734
  }) => buffer.import(bs), ([, bs], {
6689
6735
  buffer
@@ -6709,7 +6755,7 @@ const source_1 = __webpack_require__(8745);
6709
6755
  const visibility_1 = __webpack_require__(6364);
6710
6756
  const util_1 = __webpack_require__(4992);
6711
6757
  const dom_1 = __webpack_require__(394);
6712
- exports.emphasis = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('*', (source, position, range) => !source.startsWith('*', position + range)), (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank), strong_1.strong]))))), (0, source_1.str)('*'), false, [], ([, bs]) => new parser_1.List([new parser_1.Node((0, dom_1.html)('em', (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]), ([as, bs]) => bs && as.import(bs)));
6758
+ exports.emphasis = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('*', (0, visibility_1.beforeNonblankWith)(/(?!\*)/)), (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank), strong_1.strong])))), (0, source_1.str)('*'), false, [], ([, bs]) => new parser_1.List([new parser_1.Node((0, dom_1.html)('em', (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]), ([as, bs]) => bs && as.import(bs)));
6713
6759
 
6714
6760
  /***/ },
6715
6761
 
@@ -6737,13 +6783,13 @@ const subemphasis = (0, combinator_1.lazy)(() => (0, combinator_1.some)((0, comb
6737
6783
  // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
6738
6784
  // 可能な限り早く閉じるよう解析しなければならない。
6739
6785
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
6740
- exports.emstrong = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('***', (0, combinator_1.surround)('', (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank)]))), (0, source_1.strs)('*', 3), false, [], ([, bs, cs], context) => {
6786
+ exports.emstrong = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('***', visibility_1.beforeNonblank, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank)])), (0, source_1.strs)('*', 3), false, [], ([, bs, cs], context) => {
6741
6787
  const {
6742
6788
  buffer
6743
6789
  } = context;
6744
6790
  switch (cs.head.value) {
6745
6791
  case '***':
6746
- return bs;
6792
+ return buffer.import(bs);
6747
6793
  case '**':
6748
6794
  return (0, combinator_1.bind)(subemphasis, ds => {
6749
6795
  const {
@@ -6893,7 +6939,7 @@ const source_1 = __webpack_require__(8745);
6893
6939
  const visibility_1 = __webpack_require__(6364);
6894
6940
  const util_1 = __webpack_require__(4992);
6895
6941
  const dom_1 = __webpack_require__(394);
6896
- exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(32 /* State.index */, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)((0, source_1.str)('[#'), (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [[']', 1]])))), (0, source_1.str)(']'), false, [3 | 4 /* Backtrack.common */], ([, bs], context) => context.linebreak === 0 && (0, visibility_1.trimBlankNodeEnd)(bs).length > 0 ? new parser_1.List([new parser_1.Node((0, dom_1.html)('a', {
6942
+ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(32 /* State.index */, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)((0, source_1.str)('[#', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */, (0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [[']', 1]]))), (0, source_1.str)(']'), false, [3 | 4 /* Backtrack.common */], ([, bs], context) => context.linebreak === 0 && (0, visibility_1.trimBlankNodeEnd)(bs).length > 0 ? new parser_1.List([new parser_1.Node((0, dom_1.html)('a', {
6897
6943
  'data-index': dataindex(bs)
6898
6944
  }, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]) : undefined, undefined)), ns => {
6899
6945
  const el = ns.head.value;
@@ -7155,7 +7201,7 @@ const dom_1 = __webpack_require__(394);
7155
7201
  // All syntax surrounded by square brackets shouldn't contain line breaks.
7156
7202
  exports.placeholder = (0, combinator_1.lazy)(() => (0, combinator_1.surround)(
7157
7203
  // ^はabbrで使用済みだが^:などのようにして分離使用可能
7158
- (0, source_1.str)(/\[[:^|]/y), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]])))), (0, source_1.str)(']'), false, [3 | 4 /* Backtrack.common */], (_, context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
7204
+ (0, source_1.str)(/\[[:^|]/y, visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]]))), (0, source_1.str)(']'), false, [3 | 4 /* Backtrack.common */], (_, context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
7159
7205
  class: 'invalid',
7160
7206
  ...(0, util_1.invalid)('extension', 'syntax', `Invalid start symbol or linebreak`)
7161
7207
  }, context.source.slice(context.position - context.range, context.position)))]), ([as, bs]) => bs && as.import(bs)));
@@ -7302,7 +7348,7 @@ const inline_1 = __webpack_require__(7973);
7302
7348
  const visibility_1 = __webpack_require__(6364);
7303
7349
  const util_1 = __webpack_require__(4992);
7304
7350
  const dom_1 = __webpack_require__(394);
7305
- exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('++', (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '++')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '+'), true)])), '++', false, [], ([, bs], {
7351
+ exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('++', '', (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '++')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '+'), true)])), '++', false, [], ([, bs], {
7306
7352
  buffer
7307
7353
  }) => buffer.import(bs), ([, bs], {
7308
7354
  buffer
@@ -7329,7 +7375,7 @@ const dom_1 = __webpack_require__(394);
7329
7375
  // 可読性のため実際にはオブリーク体を指定する。
7330
7376
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
7331
7377
  // ある程度の長さのある文に使うのが望ましい。
7332
- exports.italic = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('///', (0, combinator_1.surround)('', (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank)), '///', false, [], ([, bs], {
7378
+ exports.italic = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('///', visibility_1.beforeNonblank, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
7333
7379
  buffer
7334
7380
  }) => buffer.import(bs), ([, bs], {
7335
7381
  buffer
@@ -7360,7 +7406,7 @@ const optspec = {
7360
7406
  rel: ['nofollow']
7361
7407
  };
7362
7408
  Object.setPrototypeOf(optspec, null);
7363
- exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.subsequence)([(0, combinator_1.constraint)(8 /* State.link */, (0, combinator_1.state)(251 /* State.linkers */, (0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.precedence)(1, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]]))), ']', true, [3 | 4 /* Backtrack.common */ | 64 /* Backtrack.link */, 2 | 32 /* Backtrack.ruby */], ([, ns = new parser_1.List()], context) => {
7409
+ exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.subsequence)([(0, combinator_1.constraint)(8 /* State.link */, (0, combinator_1.state)(251 /* State.linkers */, (0, combinator_1.dup)((0, combinator_1.surround)((0, combinator_1.close)('[', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]])), ']', true, [3 | 4 /* Backtrack.common */ | 64 /* Backtrack.link */, 2 | 32 /* Backtrack.ruby */], ([, ns = new parser_1.List()], context) => {
7364
7410
  if (context.linebreak !== 0) {
7365
7411
  const head = context.position - context.range;
7366
7412
  return void (0, combinator_1.setBacktrack)(context, 2 | 64 /* Backtrack.link */ | 32 /* Backtrack.ruby */, head);
@@ -7510,16 +7556,16 @@ const indexee_1 = __webpack_require__(7610);
7510
7556
  const visibility_1 = __webpack_require__(6364);
7511
7557
  const util_1 = __webpack_require__(4992);
7512
7558
  const dom_1 = __webpack_require__(394);
7513
- exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('==', (0, combinator_1.surround)('', (0, visibility_1.beforeNonblank)((0, combinator_1.state)(2 /* State.mark */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '==', visibility_1.afterNonblank))), '==', false, [], ([, bs], {
7559
+ exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, util_1.repeat)('==', visibility_1.beforeNonblank, (0, combinator_1.surround)('', (0, combinator_1.state)(2 /* State.mark */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '==', visibility_1.afterNonblank)), '==', false, [], ([, bs], {
7514
7560
  buffer
7515
7561
  }) => buffer.import(bs), ([, bs], {
7516
7562
  buffer
7517
7563
  }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer), (nodes, {
7518
7564
  id,
7519
7565
  state
7520
- }) => {
7566
+ }, nest) => {
7521
7567
  const el = (0, dom_1.html)('mark', (0, dom_1.defrag)((0, util_1.unwrap)(nodes)));
7522
- if (state & 251 /* State.linkers */) return new parser_1.List([new parser_1.Node(el)]);
7568
+ if (state & 251 /* State.linkers */ || nest) return new parser_1.List([new parser_1.Node(el)]);
7523
7569
  (0, dom_1.define)(el, {
7524
7570
  id: (0, indexee_1.identity)('mark', id, (0, indexee_1.signature)(el))
7525
7571
  });
@@ -7703,7 +7749,7 @@ const source_1 = __webpack_require__(8745);
7703
7749
  const visibility_1 = __webpack_require__(6364);
7704
7750
  const util_1 = __webpack_require__(4992);
7705
7751
  const dom_1 = __webpack_require__(394);
7706
- exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, (0, combinator_1.surround)((0, source_1.str)('[['), (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.beforeNonblank)((0, combinator_1.some)(inline_1.inline, ']', [[']', 1]]))]))), ']]', false, [2, 1 | 4 /* Backtrack.common */, 3 | 128 /* Backtrack.doublebracket */], ([, ns], context) => {
7752
+ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, (0, combinator_1.surround)('[[', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */, (0, combinator_1.subsequence)([abbr, (0, combinator_1.open)(visibility_1.beforeNonblank, (0, combinator_1.some)(inline_1.inline, ']', [[']', 1]]))]))), ']]', false, [2, 1 | 4 /* Backtrack.common */, 3 | 128 /* Backtrack.doublebracket */], ([, ns], context) => {
7707
7753
  const {
7708
7754
  position,
7709
7755
  range,
@@ -7948,7 +7994,7 @@ const source_1 = __webpack_require__(8745);
7948
7994
  const visibility_1 = __webpack_require__(6364);
7949
7995
  const util_1 = __webpack_require__(4992);
7950
7996
  const dom_1 = __webpack_require__(394);
7951
- exports.strong = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('**', (source, position, range) => !source.startsWith('*', position + range)), (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, visibility_1.beforeNonblank)((0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank), emphasis_1.emphasis]))))), (0, source_1.str)('**'), false, [], ([, bs]) => new parser_1.List([new parser_1.Node((0, dom_1.html)('strong', (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]), ([as, bs]) => bs && as.import(bs)));
7997
+ exports.strong = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('**', (0, visibility_1.beforeNonblankWith)(/(?!\*)/)), (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank), emphasis_1.emphasis])))), (0, source_1.str)('**'), false, [], ([, bs]) => new parser_1.List([new parser_1.Node((0, dom_1.html)('strong', (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]), ([as, bs]) => bs && as.import(bs)));
7952
7998
 
7953
7999
  /***/ },
7954
8000
 
@@ -8583,9 +8629,9 @@ Object.defineProperty(exports, "__esModule", ({
8583
8629
  }));
8584
8630
  exports.strs = exports.str = void 0;
8585
8631
  const parser_1 = __webpack_require__(605);
8586
- const combinator_1 = __webpack_require__(3484);
8587
- function str(pattern, verify) {
8588
- return (0, combinator_1.matcher)(pattern, true, verify);
8632
+ const delimiter_1 = __webpack_require__(385);
8633
+ function str(pattern, after) {
8634
+ return (0, delimiter_1.matcher)(pattern, true, after ? (0, delimiter_1.tester)(after, false) : undefined);
8589
8635
  }
8590
8636
  exports.str = str;
8591
8637
  function strs(pattern, limit = -1) {
@@ -8908,6 +8954,7 @@ Object.defineProperty(exports, "__esModule", ({
8908
8954
  }));
8909
8955
  exports.stringify = exports.unmarkInvalid = exports.markInvalid = exports.invalid = exports.repeat = exports.unwrap = void 0;
8910
8956
  const parser_1 = __webpack_require__(605);
8957
+ const delimiter_1 = __webpack_require__(385);
8911
8958
  const alias_1 = __webpack_require__(5413);
8912
8959
  const dom_1 = __webpack_require__(394);
8913
8960
  function* unwrap(nodes) {
@@ -8917,7 +8964,7 @@ function* unwrap(nodes) {
8917
8964
  }
8918
8965
  }
8919
8966
  exports.unwrap = unwrap;
8920
- function repeat(symbol, parser, cons, termination = (nodes, context, prefix, postfix) => {
8967
+ function repeat(symbol, after, parser, cons, termination = (nodes, context, prefix, postfix) => {
8921
8968
  const acc = new parser_1.List();
8922
8969
  if (prefix > 0) {
8923
8970
  acc.push(new parser_1.Node(symbol[0].repeat(prefix)));
@@ -8933,6 +8980,7 @@ function repeat(symbol, parser, cons, termination = (nodes, context, prefix, pos
8933
8980
  }
8934
8981
  return acc;
8935
8982
  }) {
8983
+ const test = (0, delimiter_1.tester)(after, false);
8936
8984
  return (0, parser_1.failsafe)(input => {
8937
8985
  const {
8938
8986
  context
@@ -8946,10 +8994,11 @@ function repeat(symbol, parser, cons, termination = (nodes, context, prefix, pos
8946
8994
  let i = symbol.length;
8947
8995
  for (; source[context.position + i] === source[context.position];) ++i;
8948
8996
  context.position += i;
8997
+ if (test(input) === undefined) return;
8949
8998
  let state = false;
8950
8999
  for (; i >= symbol.length; i -= symbol.length) {
8951
9000
  if (nodes.length > 0 && source.startsWith(symbol, context.position)) {
8952
- nodes = cons(nodes, context);
9001
+ nodes = cons(nodes, context, i > symbol.length);
8953
9002
  context.position += symbol.length;
8954
9003
  continue;
8955
9004
  }
@@ -8969,7 +9018,7 @@ function repeat(symbol, parser, cons, termination = (nodes, context, prefix, pos
8969
9018
  state = true;
8970
9019
  continue;
8971
9020
  default:
8972
- nodes = cons(nodes, context);
9021
+ nodes = cons(nodes, context, i > symbol.length);
8973
9022
  state = true;
8974
9023
  continue;
8975
9024
  }
@@ -9038,7 +9087,7 @@ exports.stringify = stringify;
9038
9087
  Object.defineProperty(exports, "__esModule", ({
9039
9088
  value: true
9040
9089
  }));
9041
- exports.trimBlankNodeEnd = exports.trimBlankEnd = exports.trimBlank = exports.isNonblankNodeStart = exports.isNonblankFirstLine = exports.beforeNonblank = exports.blankWith = exports.afterNonblank = exports.visualize = void 0;
9090
+ exports.trimBlankNodeEnd = exports.trimBlankEnd = exports.trimBlank = exports.isNonblankNodeStart = exports.isNonblankFirstLine = exports.beforeNonblankWith = exports.blankWith = exports.afterNonblank = exports.beforeNonblank = exports.visualize = void 0;
9042
9091
  const parser_1 = __webpack_require__(605);
9043
9092
  const combinator_1 = __webpack_require__(3484);
9044
9093
  const normalize_1 = __webpack_require__(4490);
@@ -9052,7 +9101,8 @@ function visualize(parser) {
9052
9101
  return (0, combinator_1.convert)(source => source.replace(blank.line, `$1${"\u001B" /* Command.Escape */}$2`), parser);
9053
9102
  }
9054
9103
  exports.visualize = visualize;
9055
- exports.afterNonblank = nonblankWith('');
9104
+ exports.beforeNonblank = beforeNonblankWith('');
9105
+ exports.afterNonblank = afterNonblankWith('');
9056
9106
  function blankWith(starts, delimiter) {
9057
9107
  return new RegExp([
9058
9108
  // 空行除去
@@ -9060,33 +9110,12 @@ function blankWith(starts, delimiter) {
9060
9110
  String.raw`(?:${starts}(?:\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)*)?`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
9061
9111
  }
9062
9112
  exports.blankWith = blankWith;
9063
- function nonblankWith(delimiter) {
9064
- return new RegExp([String.raw`(?<!\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
9065
- }
9066
- function beforeNonblank(parser) {
9067
- return input => isNonblankStart(input) ? parser(input) : undefined;
9113
+ function beforeNonblankWith(delimiter) {
9114
+ return new RegExp([typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source, String.raw`(?!\\?\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`].join(''), 'y');
9068
9115
  }
9069
- exports.beforeNonblank = beforeNonblank;
9070
- function isNonblankStart(input) {
9071
- const {
9072
- context
9073
- } = input;
9074
- const {
9075
- source,
9076
- position
9077
- } = context;
9078
- if (position === source.length) return true;
9079
- switch (source[position]) {
9080
- case ' ':
9081
- case ' ':
9082
- case '\t':
9083
- case '\n':
9084
- return false;
9085
- default:
9086
- const reg = blank.unit;
9087
- reg.lastIndex = position;
9088
- return !reg.test(source);
9089
- }
9116
+ exports.beforeNonblankWith = beforeNonblankWith;
9117
+ function afterNonblankWith(delimiter) {
9118
+ return new RegExp([String.raw`(?<!\s|&(?:${normalize_1.invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`, typeof delimiter === 'string' ? delimiter.replace(/[*+()\[\]]/g, '\\$&') : delimiter.source].join(''), 'y');
9090
9119
  }
9091
9120
  function isNonblankFirstLine(nodes) {
9092
9121
  if (nodes.length === 0) return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.296.1",
3
+ "version": "0.296.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",
@@ -1,5 +1,6 @@
1
1
  import { Parser, Input, List, Node, Context } from '../../data/parser';
2
- import { matcher, bind } from '../../../combinator';
2
+ import { tester } from '../../data/delimiter';
3
+ import { bind } from '../monad/bind';
3
4
 
4
5
  //export function contract<P extends Parser>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
5
6
  //export function contract<N>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<N>, cond: (nodes: readonly N[], rest: string) => boolean): Parser<N> {
@@ -10,8 +11,8 @@ export function validate<P extends Parser>(pattern: string | RegExp, parser: P):
10
11
  export function validate<P extends Parser>(cond: ((input: Input<Parser.Context<P>>) => boolean), parser: P): P;
11
12
  export function validate<N>(pattern: string | RegExp | ((input: Input<Context>) => boolean), parser: Parser<N>): Parser<N> {
12
13
  if (typeof pattern === 'function') return guard(pattern, parser);
13
- const match = matcher(pattern, false);
14
- return input => match(input) ? parser(input) : undefined;
14
+ const test = tester(pattern, false);
15
+ return input => test(input) && parser(input);
15
16
  }
16
17
 
17
18
  function guard<P extends Parser>(f: (input: Input<Parser.Context<P>>) => boolean, parser: P): P;
@@ -1,5 +1,5 @@
1
1
  import { Parser, input, failsafe } from '../../data/parser';
2
- import { matcher } from '../../../combinator';
2
+ import { matcher } from '../../data/delimiter';
3
3
 
4
4
  export function focus<P extends Parser>(scope: string | RegExp, parser: P, slice?: boolean): P;
5
5
  export function focus<N>(scope: string | RegExp, parser: Parser<N>, slice = true): Parser<N> {
@@ -1,50 +1,64 @@
1
1
  import { Parser, Result, List, Node, Context, failsafe } from '../../data/parser';
2
- import { matcher, clear } from '../../../combinator';
2
+ import { tester } from '../../data/delimiter';
3
3
 
4
4
  export function surround<P extends Parser, S = string>(
5
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: Parser.IntermediateParser<P>, closer: string | RegExp | Parser<S, Parser.Context<P>>,
5
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
6
+ parser: Parser.IntermediateParser<P>,
7
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
6
8
  optional?: false,
7
9
  backtracks?: readonly number[],
8
10
  f?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
9
11
  g?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
10
12
  ): P;
11
13
  export function surround<P extends Parser, S = string>(
12
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: Parser.IntermediateParser<P>, closer: string | RegExp | Parser<S, Parser.Context<P>>,
14
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
15
+ parser: Parser.IntermediateParser<P>,
16
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
13
17
  optional?: boolean,
14
18
  backtracks?: readonly number[],
15
19
  f?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
16
20
  g?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
17
21
  ): P;
18
22
  export function surround<P extends Parser, S = string>(
19
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: P, closer: string | RegExp | Parser<S, Parser.Context<P>>,
23
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
24
+ parser: P,
25
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
20
26
  optional?: false,
21
27
  backtracks?: readonly number[],
22
28
  f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
23
29
  g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
24
30
  ): P;
25
31
  export function surround<P extends Parser, S = string>(
26
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: P, closer: string | RegExp | Parser<S, Parser.Context<P>>,
32
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
33
+ parser: P,
34
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
27
35
  optional?: boolean,
28
36
  backtracks?: readonly number[],
29
37
  f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
30
38
  g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
31
39
  ): P;
32
40
  export function surround<P extends Parser<string>, S = string>(
33
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: string | RegExp | P, closer: string | RegExp | Parser<S, Parser.Context<P>>,
41
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
42
+ parser: string | RegExp | P,
43
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
34
44
  optional?: false,
35
45
  backtracks?: readonly number[],
36
46
  f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
37
47
  g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
38
48
  ): P;
39
49
  export function surround<P extends Parser<string>, S = string>(
40
- opener: string | RegExp | Parser<S, Parser.Context<P>>, parser: string | RegExp | P, closer: string | RegExp | Parser<S, Parser.Context<P>>,
50
+ opener: string | RegExp | Parser<S, Parser.Context<P>>,
51
+ parser: string | RegExp | P,
52
+ closer: string | RegExp | Parser<S, Parser.Context<P>>,
41
53
  optional?: boolean,
42
54
  backtracks?: readonly number[],
43
55
  f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
44
56
  g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
45
57
  ): P;
46
58
  export function surround<N>(
47
- opener: string | RegExp | Parser<N>, parser: string | RegExp | Parser<N>, closer: string | RegExp | Parser<N>,
59
+ opener: string | RegExp | Parser<N>,
60
+ parser: string | RegExp | Parser<N>,
61
+ closer: string | RegExp | Parser<N>,
48
62
  optional: boolean = false,
49
63
  backtracks: readonly number[] = [],
50
64
  f?: (rss: [List<Node<N>>, List<Node<N>>, List<Node<N>>], context: Context) => Result<N>,
@@ -53,19 +67,19 @@ export function surround<N>(
53
67
  switch (typeof opener) {
54
68
  case 'string':
55
69
  case 'object':
56
- opener = clear(matcher(opener, true));
70
+ opener = tester(opener, true);
57
71
  }
58
72
  assert(opener);
59
73
  switch (typeof parser) {
60
74
  case 'string':
61
75
  case 'object':
62
- parser = clear(matcher(parser, true));
76
+ parser = tester(parser, true);
63
77
  }
64
78
  assert(parser);
65
79
  switch (typeof closer) {
66
80
  case 'string':
67
81
  case 'object':
68
- closer = clear(matcher(closer, true));
82
+ closer = tester(closer, true);
69
83
  }
70
84
  assert(closer);
71
85
  const [blen, rbs, wbs] = reduce(backtracks);
@@ -76,7 +90,7 @@ export function surround<N>(
76
90
  const { linebreak } = context;
77
91
  context.linebreak = 0;
78
92
  const nodesO = opener(input);
79
- if (!nodesO) {
93
+ if (nodesO === undefined) {
80
94
  return void revert(context, linebreak);
81
95
  }
82
96
  if (rbs && isBacktrack(context, rbs, position, blen)) {
@@ -84,14 +98,14 @@ export function surround<N>(
84
98
  }
85
99
  const nodesM = context.position < source.length ? parser(input) : undefined;
86
100
  context.range = context.position - position;
87
- if (!nodesM && !optional) {
101
+ if (nodesM === undefined && !optional) {
88
102
  wbs && setBacktrack(context, wbs, position);
89
103
  const result = g?.([nodesO, nodesM], context);
90
104
  return result || void revert(context, linebreak);
91
105
  }
92
106
  const nodesC = nodesM || optional ? closer(input) : undefined;
93
107
  context.range = context.position - position;
94
- if (!nodesC) {
108
+ if (nodesC === undefined) {
95
109
  wbs && setBacktrack(context, wbs, position);
96
110
  const result = g?.([nodesO, nodesM], context);
97
111
  return result || void revert(context, linebreak);
@@ -102,7 +116,9 @@ export function surround<N>(
102
116
  context.range = context.position - position;
103
117
  const result = f
104
118
  ? f([nodesO, nodesM!, nodesC], context)
105
- : nodesO.import(nodesM ?? new List()).import(nodesC);
119
+ : nodesM
120
+ ? nodesO.import(nodesM).import(nodesC)
121
+ : nodesO.import(nodesC);
106
122
  if (result) {
107
123
  context.linebreak ||= linebreak;
108
124
  }
@@ -1,5 +1,5 @@
1
- import { Input, Context } from './parser';
2
- import { matcher } from '../../combinator';
1
+ import { Parser, Input, List, Node, Context } from './parser';
2
+ import { consume } from './parser/context';
3
3
 
4
4
  interface Delimiter {
5
5
  readonly memory: Delimiter[];
@@ -33,11 +33,11 @@ export class Delimiters {
33
33
  return () => undefined;
34
34
  case 'string':
35
35
  case 'object':
36
- const match = matcher(pattern, false);
37
- const verify = after ? matcher(after, false) : undefined;
36
+ const test = tester(pattern, false);
37
+ const verify = after ? tester(after, false) : undefined;
38
38
  return verify
39
- ? input => match(input) !== undefined && verify(input) !== undefined || undefined
40
- : input => match(input) !== undefined || undefined;
39
+ ? input => test(input) !== undefined && verify(input) !== undefined || undefined
40
+ : input => test(input) !== undefined || undefined;
41
41
  }
42
42
  }
43
43
  private readonly tree: Record<number, Delimiter[]> = {};
@@ -150,3 +150,79 @@ export class Delimiters {
150
150
  return false;
151
151
  }
152
152
  }
153
+
154
+ export function matcher(pattern: string | RegExp, advance: boolean, after?: Parser<string>): Parser<string> {
155
+ assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
156
+ const count = typeof pattern === 'object'
157
+ ? /[^^\\*+][*+]/.test(pattern.source)
158
+ : false;
159
+ switch (typeof pattern) {
160
+ case 'string':
161
+ if (pattern === '') return () => new List([new Node(pattern)]);
162
+ return input => {
163
+ const { context } = input;
164
+ const { source, position } = context;
165
+ if (!source.startsWith(pattern, position)) return;
166
+ if (advance) {
167
+ context.position += pattern.length;
168
+ }
169
+ const next = after?.(input);
170
+ return after
171
+ ? next && new List([new Node(pattern)]).import(next)
172
+ : new List([new Node(pattern)]);
173
+ };
174
+ case 'object':
175
+ assert(pattern.sticky);
176
+ return input => {
177
+ const { context } = input;
178
+ const { source, position } = context;
179
+ pattern.lastIndex = position;
180
+ if (!pattern.test(source)) return;
181
+ const src = source.slice(position, pattern.lastIndex);
182
+ count && consume(src.length, context);
183
+ if (advance) {
184
+ context.position += src.length;
185
+ }
186
+ const next = after?.(input);
187
+ return after
188
+ ? next && new List([new Node(src)]).import(next)
189
+ : new List([new Node(src)]);
190
+ };
191
+ }
192
+ }
193
+
194
+ export function tester(pattern: string | RegExp, advance: boolean, after?: Parser<unknown>): Parser<never> {
195
+ assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
196
+ const count = typeof pattern === 'object'
197
+ ? /[^^\\*+][*+]/.test(pattern.source)
198
+ : false;
199
+ switch (typeof pattern) {
200
+ case 'string':
201
+ if (pattern === '') return () => new List();
202
+ return input => {
203
+ const { context } = input;
204
+ const { source, position } = context;
205
+ if (!source.startsWith(pattern, position)) return;
206
+ if (advance) {
207
+ context.position += pattern.length;
208
+ }
209
+ if (after && after(input) === undefined) return;
210
+ return new List();
211
+ };
212
+ case 'object':
213
+ assert(pattern.sticky);
214
+ return input => {
215
+ const { context } = input;
216
+ const { source, position } = context;
217
+ pattern.lastIndex = position;
218
+ if (!pattern.test(source)) return;
219
+ const len = pattern.lastIndex - position;
220
+ count && consume(len, context);
221
+ if (advance) {
222
+ context.position += len;
223
+ }
224
+ if (after && after(input) === undefined) return;
225
+ return new List();
226
+ };
227
+ }
228
+ }
@@ -1,4 +1,4 @@
1
- import { Parser, Result, List, Node, Context, Options } from '../../data/parser';
1
+ import { Parser, Result, Context, Options } from '../../data/parser';
2
2
  import { min } from 'spica/alias';
3
3
  import { clone } from 'spica/assign';
4
4
 
@@ -158,36 +158,3 @@ export function constraint<N>(state: number, positive: boolean | Parser<N>, pars
158
158
  : undefined;
159
159
  };
160
160
  }
161
-
162
- export function matcher(pattern: string | RegExp, advance: boolean, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
163
- assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
164
- const count = typeof pattern === 'object'
165
- ? /[^^\\*+][*+]/.test(pattern.source)
166
- : false;
167
- switch (typeof pattern) {
168
- case 'string':
169
- return ({ context }) => {
170
- const { source, position } = context;
171
- if (!source.startsWith(pattern, position)) return;
172
- if (verify?.(source, position, pattern.length) === false) return;
173
- if (advance) {
174
- context.position += pattern.length;
175
- }
176
- return new List([new Node(pattern)]);
177
- };
178
- case 'object':
179
- assert(pattern.sticky);
180
- return ({ context }) => {
181
- const { source, position } = context;
182
- pattern.lastIndex = position;
183
- if (!pattern.test(source)) return;
184
- const src = source.slice(position, pattern.lastIndex);
185
- count && consume(src.length, context);
186
- if (verify?.(source, position, src.length) === false) return;
187
- if (advance) {
188
- context.position += src.length;
189
- }
190
- return new List([new Node(src)]);
191
- };
192
- }
193
- }
@@ -1,16 +1,16 @@
1
1
  import { AnnotationParser } from '../inline';
2
2
  import { State, Backtrack } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, precedence, state, constraint, surround, setBacktrack, lazy } from '../../combinator';
4
+ import { union, some, precedence, state, constraint, surround, close, setBacktrack, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
7
7
  import { unwrap } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, surround(
11
- '((',
11
+ close('((', beforeNonblank),
12
12
  precedence(1, state(State.annotation,
13
- beforeNonblank(some(union([inline]), ')', [[')', 1]])))),
13
+ some(union([inline]), ')', [[')', 1]]))),
14
14
  '))',
15
15
  false,
16
16
  [2, 1 | Backtrack.common, 3 | Backtrack.doublebracket],
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const deletion: DeletionParser = lazy(() =>
11
- precedence(0, recursion(Recursion.inline, repeat('~~', surround(
11
+ precedence(0, recursion(Recursion.inline, repeat('~~', '', surround(
12
12
  '',
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '~~')),
@@ -5,17 +5,17 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
5
5
  import { inline } from '../inline';
6
6
  import { strong } from './strong';
7
7
  import { str } from '../source';
8
- import { beforeNonblank, afterNonblank } from '../visibility';
8
+ import { beforeNonblankWith, afterNonblank } from '../visibility';
9
9
  import { unwrap } from '../util';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const emphasis: EmphasisParser = lazy(() => surround(
13
- str('*', (source, position, range) => !source.startsWith('*', position + range)),
13
+ str('*', beforeNonblankWith(/(?!\*)/)),
14
14
  precedence(0, recursion(Recursion.inline,
15
- beforeNonblank(some(union([
15
+ some(union([
16
16
  some(inline, '*', afterNonblank),
17
17
  strong,
18
- ]))))),
18
+ ])))),
19
19
  str('*'),
20
20
  false, [],
21
21
  ([, bs]) => new List([new Node(html('em', defrag(unwrap(bs))))]),
@@ -114,6 +114,7 @@ describe('Unit: parser/inline/emstrong', () => {
114
114
  assert.deepStrictEqual(inspect(parser, input('******a*b ***', new Context())), [['*****', '<em>a</em>', 'b ', '***'], '']);
115
115
  assert.deepStrictEqual(inspect(parser, input('******a*b ****', new Context())), [['*****', '<em>a</em>', 'b ', '****'], '']);
116
116
  assert.deepStrictEqual(inspect(parser, input('******a*b *****', new Context())), [['*****', '<em>a</em>', 'b ', '*****'], '']);
117
+ assert.deepStrictEqual(inspect(parser, input('******a*** b***', new Context())), [['<em><strong><em><strong>a</strong></em> b</strong></em>'], '']);
117
118
  });
118
119
 
119
120
  });
@@ -23,9 +23,9 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
23
23
  // 可能な限り早く閉じるよう解析しなければならない。
24
24
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
25
25
  export const emstrong: EmStrongParser = lazy(() =>
26
- precedence(0, recursion(Recursion.inline, repeat('***', surround(
26
+ precedence(0, recursion(Recursion.inline, repeat('***', beforeNonblank, surround(
27
27
  '',
28
- beforeNonblank(some(union([some(inline, '*', afterNonblank)]))),
28
+ some(union([some(inline, '*', afterNonblank)])),
29
29
  strs('*', 3),
30
30
  false, [],
31
31
  ([, bs, cs], context): Result<Parser.Node<EmStrongParser>, Parser.Context<EmStrongParser>> => {
@@ -33,7 +33,7 @@ export const emstrong: EmStrongParser = lazy(() =>
33
33
  const { buffer } = context;
34
34
  switch (cs.head!.value) {
35
35
  case '***':
36
- return bs;
36
+ return buffer.import(bs);
37
37
  case '**':
38
38
  return bind<EmphasisParser>(
39
39
  subemphasis,
@@ -13,13 +13,12 @@ import { html, define, defrag } from 'typed-dom/dom';
13
13
  import IndexParser = ExtensionParser.IndexParser;
14
14
 
15
15
  export const index: IndexParser = lazy(() => constraint(State.index, fmap(indexee(surround(
16
- str('[#'),
16
+ str('[#', beforeNonblank),
17
17
  precedence(1, state(State.linkers,
18
- beforeNonblank(
19
18
  some(inits([
20
19
  inline,
21
20
  signature,
22
- ]), ']', [[']', 1]])))),
21
+ ]), ']', [[']', 1]]))),
23
22
  str(']'),
24
23
  false,
25
24
  [3 | Backtrack.common],
@@ -14,9 +14,9 @@ import { html } from 'typed-dom/dom';
14
14
 
15
15
  export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surround(
16
16
  // ^はabbrで使用済みだが^:などのようにして分離使用可能
17
- str(/\[[:^|]/y),
17
+ str(/\[[:^|]/y, beforeNonblank),
18
18
  precedence(1, recursion(Recursion.inline,
19
- beforeNonblank(some(union([inline]), ']', [[']', 1]])))),
19
+ some(union([inline]), ']', [[']', 1]]))),
20
20
  str(']'),
21
21
  false,
22
22
  [3 | Backtrack.common],
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() =>
11
- precedence(0, recursion(Recursion.inline, repeat('++', surround(
11
+ precedence(0, recursion(Recursion.inline, repeat('++', '', surround(
12
12
  '',
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '++')),
@@ -57,6 +57,7 @@ describe('Unit: parser/inline/italic', () => {
57
57
  assert.deepStrictEqual(inspect(parser, input('//////a/////b', new Context())), [['///', '<i>a</i>', '//b'], '']);
58
58
  assert.deepStrictEqual(inspect(parser, input('//////a//////', new Context())), [['<i><i>a</i></i>'], '']);
59
59
  assert.deepStrictEqual(inspect(parser, input('//////a///b///', new Context())), [['<i><i>a</i>b</i>'], '']);
60
+ assert.deepStrictEqual(inspect(parser, input('//////a/// b///', new Context())), [['<i><i>a</i> b</i>'], '']);
60
61
  assert.deepStrictEqual(inspect(parser, input('///a ///b//////', new Context())), [['<i>a <i>b</i></i>'], '']);
61
62
  assert.deepStrictEqual(inspect(parser, input('///- ///b//////', new Context())), [['<i>- <i>b</i></i>'], '']);
62
63
  assert.deepStrictEqual(inspect(parser, input('///a\\ ///b//////', new Context())), [['<i>a <i>b</i></i>'], '']);
@@ -11,9 +11,9 @@ import { html, defrag } from 'typed-dom/dom';
11
11
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
12
12
  // ある程度の長さのある文に使うのが望ましい。
13
13
  export const italic: ItalicParser = lazy(() =>
14
- precedence(0, recursion(Recursion.inline, repeat('///', surround(
14
+ precedence(0, recursion(Recursion.inline, repeat('///', beforeNonblank, surround(
15
15
  '',
16
- beforeNonblank(some(union([inline]), '///', afterNonblank)),
16
+ some(union([inline]), '///', afterNonblank),
17
17
  '///',
18
18
  false, [],
19
19
  ([, bs], { buffer }) => buffer.import(bs),
@@ -1,7 +1,7 @@
1
1
  import { LinkParser } from '../inline';
2
2
  import { Context, State, Backtrack, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
4
+ import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, close, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { str } from '../source';
@@ -18,9 +18,9 @@ Object.setPrototypeOf(optspec, null);
18
18
  export const textlink: LinkParser.TextLinkParser = lazy(() => bind(
19
19
  subsequence([
20
20
  constraint(State.link, state(State.linkers, dup(surround(
21
- '[',
21
+ close('[', beforeNonblank),
22
22
  precedence(1,
23
- beforeNonblank(some(union([inline]), ']', [[']', 1]]))),
23
+ some(union([inline]), ']', [[']', 1]])),
24
24
  ']',
25
25
  true,
26
26
  [3 | Backtrack.common | Backtrack.link, 2 | Backtrack.ruby],
@@ -44,6 +44,7 @@ describe('Unit: parser/inline/mark', () => {
44
44
  assert.deepStrictEqual(inspect(parser, input('==a&Tab;==b====', new Context())), [['<mark id="mark::a_b=33Mw2l">a\t<mark>b</mark></mark>', '<a href="#mark::a_b=33Mw2l"></a>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser, input('==a<wbr>==b====', new Context())), [['<mark id="mark::ab">a<wbr><mark>b</mark></mark>', '<a href="#mark::ab"></a>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser, input('==*==a==*==', new Context())), [['<mark id="mark::a"><em><mark>a</mark></em></mark>', '<a href="#mark::a"></a>'], '']);
47
+ assert.deepStrictEqual(inspect(parser, input('====a== b==', new Context())), [['<mark id="mark::a_b"><mark>a</mark> b</mark>', '<a href="#mark::a_b"></a>'], '']);
47
48
  });
48
49
 
49
50
  });
@@ -9,16 +9,16 @@ import { unwrap, repeat } from '../util';
9
9
  import { html, define, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const mark: MarkParser = lazy(() =>
12
- precedence(0, recursion(Recursion.inline, repeat('==', surround(
12
+ precedence(0, recursion(Recursion.inline, repeat('==', beforeNonblank, surround(
13
13
  '',
14
- beforeNonblank(state(State.mark, some(union([inline]), '==', afterNonblank))),
14
+ state(State.mark, some(union([inline]), '==', afterNonblank)),
15
15
  '==',
16
16
  false, [],
17
17
  ([, bs], { buffer }) => buffer.import(bs),
18
18
  ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
19
- (nodes, { id, state }) => {
19
+ (nodes, { id, state }, nest) => {
20
20
  const el = html('mark', defrag(unwrap(nodes)));
21
- if (state & State.linkers) return new List([new Node(el)]);
21
+ if (state & State.linkers || nest) return new List([new Node(el)]);
22
22
  define(el, { id: identity('mark', id, signature(el)) });
23
23
  return el.id
24
24
  ? new List([new Node(el), new Node(html('a', { href: `#${el.id}` }))])
@@ -1,7 +1,7 @@
1
1
  import { ReferenceParser } from '../inline';
2
2
  import { State, Backtrack, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, subsequence, some, precedence, state, constraint, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
4
+ import { union, subsequence, some, precedence, state, constraint, surround, open, isBacktrack, setBacktrack, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { textlink } from './link';
7
7
  import { str } from '../source';
@@ -10,11 +10,11 @@ import { unwrap, invalid } from '../util';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const reference: ReferenceParser = lazy(() => constraint(State.reference, surround(
13
- str('[['),
13
+ '[[',
14
14
  precedence(1, state(State.annotation | State.reference,
15
15
  subsequence([
16
16
  abbr,
17
- beforeNonblank(some(inline, ']', [[']', 1]])),
17
+ open(beforeNonblank, some(inline, ']', [[']', 1]])),
18
18
  ]))),
19
19
  ']]',
20
20
  false,
@@ -5,17 +5,17 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
5
5
  import { inline } from '../inline';
6
6
  import { emphasis } from './emphasis';
7
7
  import { str } from '../source';
8
- import { beforeNonblank, afterNonblank } from '../visibility';
8
+ import { beforeNonblankWith, afterNonblank } from '../visibility';
9
9
  import { unwrap } from '../util';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const strong: StrongParser = lazy(() => surround(
13
- str('**', (source, position, range) => !source.startsWith('*', position + range)),
13
+ str('**', beforeNonblankWith(/(?!\*)/)),
14
14
  precedence(0, recursion(Recursion.inline,
15
- beforeNonblank(some(union([
15
+ some(union([
16
16
  some(inline, '*', afterNonblank),
17
17
  emphasis,
18
- ]))))),
18
+ ])))),
19
19
  str('**'),
20
20
  false, [],
21
21
  ([, bs]) => new List([new Node(html('strong', defrag(unwrap(bs))))]),
@@ -1,10 +1,10 @@
1
1
  import { StrParser } from '../source';
2
2
  import { Parser, List, Node } from '../../combinator/data/parser';
3
- import { matcher } from '../../combinator';
3
+ import { matcher, tester } from '../../combinator/data/delimiter';
4
4
 
5
- export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): StrParser;
6
- export function str(pattern: string | RegExp, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
7
- return matcher(pattern, true, verify);
5
+ export function str(pattern: string | RegExp, after?: string | RegExp): StrParser;
6
+ export function str(pattern: string | RegExp, after?: string | RegExp): Parser<string> {
7
+ return matcher(pattern, true, after ? tester(after, false) : undefined);
8
8
  }
9
9
 
10
10
  export function strs(pattern: string, limit?: number): StrParser;
@@ -1,4 +1,5 @@
1
1
  import { Parser, Result, List, Node, failsafe } from '../combinator/data/parser';
2
+ import { tester } from '../combinator/data/delimiter';
2
3
  import { Context, Command } from './context';
3
4
  import { min } from 'spica/alias';
4
5
  import { define } from 'typed-dom/dom';
@@ -10,8 +11,8 @@ export function* unwrap<N>(nodes: List<Node<N>> | undefined): Iterable<N> {
10
11
  }
11
12
  }
12
13
 
13
- export function repeat<P extends Parser<HTMLElement | string, Context>>(symbol: string, parser: P, cons: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>) => List<Node<Parser.Node<P>>>, termination?: (acc: List<Node<Parser.Node<P>>>, context: Context, prefix: number, postfix: number, state: boolean) => Result<string | Parser.Node<P>>): P;
14
- export function repeat<N extends HTMLElement | string>(symbol: string, parser: Parser<N>, cons: (nodes: List<Node<N>>, context: Context) => List<Node<N>>, termination: (acc: List<Node<N>>, context: Context, prefix: number, postfix: number, state: boolean) => Result<string | N, Context> = (nodes, context, prefix, postfix) => {
14
+ export function repeat<P extends Parser<HTMLElement | string, Context>>(symbol: string, after: string | RegExp, parser: P, cons: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>, nest: boolean) => List<Node<Parser.Node<P>>>, termination?: (acc: List<Node<Parser.Node<P>>>, context: Context, prefix: number, postfix: number, state: boolean) => Result<string | Parser.Node<P>>): P;
15
+ export function repeat<N extends HTMLElement | string>(symbol: string, after: string | RegExp, parser: Parser<N>, cons: (nodes: List<Node<N>>, context: Context, nest: boolean) => List<Node<N>>, termination: (acc: List<Node<N>>, context: Context, prefix: number, postfix: number, state: boolean) => Result<string | N, Context> = (nodes, context, prefix, postfix) => {
15
16
  const acc = new List<Node<string | N>>();
16
17
  if (prefix > 0) {
17
18
  acc.push(new Node(symbol[0].repeat(prefix)));
@@ -24,6 +25,7 @@ export function repeat<N extends HTMLElement | string>(symbol: string, parser: P
24
25
  }
25
26
  return acc;
26
27
  }): Parser<string | N, Context> {
28
+ const test = tester(after, false);
27
29
  return failsafe(input => {
28
30
  const { context } = input;
29
31
  const { source, position } = context;
@@ -32,10 +34,11 @@ export function repeat<N extends HTMLElement | string>(symbol: string, parser: P
32
34
  let i = symbol.length;
33
35
  for (; source[context.position + i] === source[context.position];) ++i;
34
36
  context.position += i;
37
+ if (test(input) === undefined) return;
35
38
  let state = false;
36
39
  for (; i >= symbol.length; i -= symbol.length) {
37
40
  if (nodes.length > 0 && source.startsWith(symbol, context.position)) {
38
- nodes = cons(nodes, context);
41
+ nodes = cons(nodes, context, i > symbol.length);
39
42
  context.position += symbol.length;
40
43
  continue;
41
44
  }
@@ -57,7 +60,7 @@ export function repeat<N extends HTMLElement | string>(symbol: string, parser: P
57
60
  state = true;
58
61
  continue;
59
62
  default:
60
- nodes = cons(nodes, context);
63
+ nodes = cons(nodes, context, i > symbol.length);
61
64
  state = true;
62
65
  continue;
63
66
  }
@@ -1,5 +1,5 @@
1
- import { Parser, Input, List, Node, failsafe } from '../combinator/data/parser';
2
- import { Context, Command } from './context';
1
+ import { Parser, List, Node, failsafe } from '../combinator/data/parser';
2
+ import { Command } from './context';
3
3
  import { Flag } from './node';
4
4
  import { convert, fmap } from '../combinator';
5
5
  import { invisibleBlankHTMLEntityNames } from './api/normalize';
@@ -25,7 +25,8 @@ export function visualize<P extends Parser>(parser: P): P {
25
25
  parser);
26
26
  }
27
27
 
28
- export const afterNonblank = nonblankWith('');
28
+ export const beforeNonblank = beforeNonblankWith('');
29
+ export const afterNonblank = afterNonblankWith('');
29
30
  export function blankWith(starts: '\n', delimiter: string | RegExp): RegExp {
30
31
  return new RegExp([
31
32
  // 空行除去
@@ -36,37 +37,21 @@ export function blankWith(starts: '\n', delimiter: string | RegExp): RegExp {
36
37
  : delimiter.source,
37
38
  ].join(''), 'y');
38
39
  }
39
- function nonblankWith(delimiter: string | RegExp): RegExp {
40
+ export function beforeNonblankWith(delimiter: string | RegExp): RegExp {
40
41
  return new RegExp([
41
- String.raw`(?<!\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`,
42
42
  typeof delimiter === 'string'
43
43
  ? delimiter.replace(/[*+()\[\]]/g, '\\$&')
44
44
  : delimiter.source,
45
+ String.raw`(?!\\?\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`,
45
46
  ].join(''), 'y');
46
47
  }
47
-
48
- export function beforeNonblank<P extends Parser>(parser: P): P;
49
- export function beforeNonblank<N>(parser: Parser<N>): Parser<N, Context> {
50
- return input =>
51
- isNonblankStart(input)
52
- ? parser(input)
53
- : undefined;
54
- }
55
- function isNonblankStart(input: Input<Context>): boolean {
56
- const { context } = input;
57
- const { source, position } = context;
58
- if (position === source.length) return true;
59
- switch (source[position]) {
60
- case ' ':
61
- case ' ':
62
- case '\t':
63
- case '\n':
64
- return false;
65
- default:
66
- const reg = blank.unit;
67
- reg.lastIndex = position;
68
- return !reg.test(source);
69
- }
48
+ function afterNonblankWith(delimiter: string | RegExp): RegExp {
49
+ return new RegExp([
50
+ String.raw`(?<!\s|&(?:${invisibleBlankHTMLEntityNames.join('|')});|<wbr ?>)`,
51
+ typeof delimiter === 'string'
52
+ ? delimiter.replace(/[*+()\[\]]/g, '\\$&')
53
+ : delimiter.source,
54
+ ].join(''), 'y');
70
55
  }
71
56
 
72
57
  export function isNonblankFirstLine(nodes: List<Node<HTMLElement | string>>): boolean {