securemark 0.298.3 → 0.298.5

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.298.5
4
+
5
+ - Refactoring.
6
+
7
+ ## 0.298.4
8
+
9
+ - Refactoring.
10
+
3
11
  ## 0.298.3
4
12
 
5
13
  - Refactoring.
package/design.md CHANGED
@@ -300,11 +300,7 @@ Securemarkはスーパークラス構文が解析に失敗した入力をサブ
300
300
 
301
301
  ### 実行性能
302
302
 
303
- 構文数と使用記号数が大きく異なるため単純な比較はできないが直接比較してもにブラウザによるHTMLパース時間を含めたCommonMarkとの速度差は4倍、CommonMarkの問題の解決を試みたdjotとの速度差は等倍程度でありすでに十分高速である。
304
-
305
- そのほかブラウザの以下の欠陥および低速性により速度低下が生じており今後のブラウザの改善が求められる。
306
-
307
- - IntersectionObserverが描画完了前に交差を計算するためすべて同時発火する欠陥
303
+ 構文数と使用記号数が大きく異なるため単純な比較はできないが直接比較してもにブラウザによるHTMLパース時間を含めた速度差はCommonMarkの1/3、CommonMarkの問題の解決を試みたdjotと同等程度でありすでに十分高速である。
308
304
 
309
305
  ### 最適化
310
306
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.298.3 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.298.5 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"));
@@ -4163,12 +4163,12 @@ const note_1 = __webpack_require__(165);
4163
4163
  const url_1 = __webpack_require__(1904);
4164
4164
  const array_1 = __webpack_require__(6876);
4165
4165
  function bind(target, settings) {
4166
- const context = new context_1.Context({
4166
+ const options = {
4167
4167
  ...settings,
4168
4168
  host: settings.host ?? new url_1.ReadonlyURL(location.pathname, location.origin)
4169
- });
4170
- if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4171
- if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
4169
+ };
4170
+ if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4171
+ if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
4172
4172
  const blocks = [];
4173
4173
  const adds = [];
4174
4174
  const dels = [];
@@ -4183,11 +4183,11 @@ function bind(target, settings) {
4183
4183
  if (settings.chunk && revision) throw new Error('Chunks cannot be updated');
4184
4184
  const url = (0, header_1.headers)(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
4185
4185
  // @ts-expect-error
4186
- context.url = url ? new url_1.ReadonlyURL(url) : undefined;
4186
+ options.url = url ? new url_1.ReadonlyURL(url) : undefined;
4187
4187
  const rev = revision = Symbol();
4188
4188
  const sourceSegments = [];
4189
4189
  const sourceSegmentAttrs = [];
4190
- for (const [seg, attr] of (0, segment_1.segment)(source, !context.local)) {
4190
+ for (const [seg, attr] of (0, segment_1.segment)(source, true)) {
4191
4191
  sourceSegments.push(seg);
4192
4192
  sourceSegmentAttrs.push(attr);
4193
4193
  yield {
@@ -4210,15 +4210,15 @@ function bind(target, settings) {
4210
4210
  const base = next(head);
4211
4211
  let index = head;
4212
4212
  // @ts-expect-error
4213
- context.header = true;
4213
+ options.header = true;
4214
4214
  for (; index < sourceSegments.length - last; ++index) {
4215
4215
  const seg = sourceSegments[index];
4216
- context.segment = sourceSegmentAttrs[index] | 1 /* Segment.write */;
4217
- const es = (0, block_1.block)((0, parser_1.input)(seg, new context_1.Context(context))).foldl((acc, {
4216
+ options.segment = sourceSegmentAttrs[index] | 1 /* Segment.write */;
4217
+ const es = (0, block_1.block)((0, parser_1.input)(seg, new context_1.Context(options))).foldl((acc, {
4218
4218
  value
4219
4219
  }) => void acc.push(value) || acc, []);
4220
4220
  // @ts-expect-error
4221
- context.header = false;
4221
+ options.header = false;
4222
4222
  blocks.length === index ? blocks.push([seg, es, url]) : blocks.splice(index, 0, [seg, es, url]);
4223
4223
  if (es.length === 0) continue;
4224
4224
  // All deletion processes always run after all addition processes have done.
@@ -4272,7 +4272,7 @@ function bind(target, settings) {
4272
4272
  if (rev !== revision) return yield {
4273
4273
  type: 'cancel'
4274
4274
  };
4275
- for (const el of (0, figure_1.figure)(next(0)?.parentNode ?? target, settings.notes, context)) {
4275
+ for (const el of (0, figure_1.figure)(next(0)?.parentNode ?? target, settings.notes, options)) {
4276
4276
  el ? yield {
4277
4277
  type: 'figure',
4278
4278
  value: el
@@ -4283,7 +4283,7 @@ function bind(target, settings) {
4283
4283
  type: 'cancel'
4284
4284
  };
4285
4285
  }
4286
- for (const el of (0, note_1.note)(next(0)?.parentNode ?? target, settings.notes, context, bottom)) {
4286
+ for (const el of (0, note_1.note)(next(0)?.parentNode ?? target, settings.notes, options, bottom)) {
4287
4287
  el ? yield {
4288
4288
  type: 'note',
4289
4289
  value: el
@@ -4512,34 +4512,34 @@ const figure_1 = __webpack_require__(1657);
4512
4512
  const note_1 = __webpack_require__(165);
4513
4513
  const url_1 = __webpack_require__(1904);
4514
4514
  const dom_1 = __webpack_require__(394);
4515
- function parse(source, options = {}, context) {
4515
+ function parse(source, opts = {}, options) {
4516
4516
  const url = (0, header_1.headers)(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
4517
- context = new context_1.Context({
4518
- host: options.host ?? context?.host ?? new url_1.ReadonlyURL(location.pathname, location.origin),
4519
- url: url ? new url_1.ReadonlyURL(url) : context?.url,
4520
- id: options.id ?? context?.id,
4521
- local: options.local ?? context?.local,
4522
- caches: context?.caches,
4523
- resources: context?.resources
4524
- });
4525
- if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4526
- if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
4517
+ options = {
4518
+ host: opts.host ?? options?.host ?? new url_1.ReadonlyURL(location.pathname, location.origin),
4519
+ url: url ? new url_1.ReadonlyURL(url) : options?.url,
4520
+ id: opts.id ?? options?.id,
4521
+ local: opts.local ?? options?.local ?? false,
4522
+ caches: options?.caches,
4523
+ resources: options?.resources
4524
+ };
4525
+ if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4526
+ if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
4527
4527
  const node = (0, dom_1.frag)();
4528
4528
  // @ts-expect-error
4529
- context.header = true;
4530
- for (const [seg, attr] of (0, segment_1.segment)(source, !context.local)) {
4531
- context.segment = attr | 1 /* Segment.write */;
4532
- const es = (0, block_1.block)((0, parser_1.input)(seg, new context_1.Context(context))).foldl((acc, {
4529
+ options.header = true;
4530
+ for (const [seg, attr] of (0, segment_1.segment)(source, !options.local)) {
4531
+ options.segment = attr | 1 /* Segment.write */;
4532
+ const es = (0, block_1.block)((0, parser_1.input)(seg, new context_1.Context(options))).foldl((acc, {
4533
4533
  value
4534
4534
  }) => void acc.push(value) || acc, []);
4535
4535
  // @ts-expect-error
4536
- context.header = false;
4536
+ options.header = false;
4537
4537
  if (es.length === 0) continue;
4538
4538
  node.append(...es);
4539
4539
  }
4540
- if (options.test) return node;
4541
- for (const _ of (0, figure_1.figure)(node, options.notes, context));
4542
- for (const _ of (0, note_1.note)(node, options.notes, context));
4540
+ if (opts.test) return node;
4541
+ for (const _ of (0, figure_1.figure)(node, opts.notes, options));
4542
+ for (const _ of (0, note_1.note)(node, opts.notes, options));
4543
4543
  return node;
4544
4544
  }
4545
4545
  exports.parse = parse;
@@ -4575,7 +4575,6 @@ Object.defineProperty(exports, "__esModule", ({
4575
4575
  exports.block = void 0;
4576
4576
  const parser_1 = __webpack_require__(605);
4577
4577
  const combinator_1 = __webpack_require__(3484);
4578
- const segment_1 = __webpack_require__(3967);
4579
4578
  const header_1 = __webpack_require__(3009);
4580
4579
  const source_1 = __webpack_require__(8745);
4581
4580
  const pagebreak_1 = __webpack_require__(2946);
@@ -4598,13 +4597,7 @@ const reply_1 = __webpack_require__(3832);
4598
4597
  const paragraph_1 = __webpack_require__(4330);
4599
4598
  const random_1 = __webpack_require__(3158);
4600
4599
  const dom_1 = __webpack_require__(394);
4601
- exports.block = (0, combinator_1.reset)({
4602
- resources: {
4603
- // バックトラックのせいで文字数制限を受けないようにする。
4604
- clock: segment_1.MAX_SEGMENT_SIZE * 6 + 1,
4605
- recursions: [5 || 0 /* Recursion.block */, 20 || 0 /* Recursion.blockquote */, 40 || 0 /* Recursion.listitem */, 20 || 0 /* Recursion.inline */, 20 || 0 /* Recursion.annotation */, 20 || 0 /* Recursion.bracket */, 20 || 0 /* Recursion.terminal */]
4606
- }
4607
- }, error((0, combinator_1.union)([source_1.emptysegment, input => {
4600
+ exports.block = error((0, combinator_1.union)([source_1.emptysegment, input => {
4608
4601
  const {
4609
4602
  source,
4610
4603
  position,
@@ -4665,7 +4658,7 @@ exports.block = (0, combinator_1.reset)({
4665
4658
  default:
4666
4659
  if ('0' <= char && char <= '9') return (0, olist_1.olist)(input);
4667
4660
  }
4668
- }, paragraph_1.paragraph])));
4661
+ }, paragraph_1.paragraph]));
4669
4662
  function error(parser) {
4670
4663
  const reg = new RegExp(String.raw`^${"\u0007" /* Command.Error */}[^\r\n]*\r?\n`);
4671
4664
  return (0, combinator_1.recover)(parser, ({
@@ -6011,8 +6004,10 @@ function format(list) {
6011
6004
  Object.defineProperty(exports, "__esModule", ({
6012
6005
  value: true
6013
6006
  }));
6014
- exports.CmdRegExp = exports.Context = void 0;
6007
+ exports.CmdRegExp = exports.Context = exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE = void 0;
6015
6008
  const parser_1 = __webpack_require__(605);
6009
+ exports.MAX_SEGMENT_SIZE = 100_000; // 100,000 bytes (Max value size of FDB)
6010
+ exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE * 10;
6016
6011
  class Context extends parser_1.Context {
6017
6012
  constructor(options = {}) {
6018
6013
  super(options);
@@ -6028,6 +6023,11 @@ class Context extends parser_1.Context {
6028
6023
  id,
6029
6024
  caches
6030
6025
  } = options;
6026
+ this.resources ??= {
6027
+ // バックトラックのせいで文字数制限を受けないようにする。
6028
+ clock: exports.MAX_SEGMENT_SIZE * (6 + 1),
6029
+ recursions: [5 || 0 /* Recursion.block */, 20 || 0 /* Recursion.blockquote */, 40 || 0 /* Recursion.listitem */, 20 || 0 /* Recursion.inline */, 20 || 0 /* Recursion.annotation */, 20 || 0 /* Recursion.bracket */, 20 || 0 /* Recursion.terminal */]
6030
+ };
6031
6031
  this.segment = segment ?? 0 /* Segment.unknown */;
6032
6032
  this.local = local ?? false;
6033
6033
  this.sequential = sequential ?? false;
@@ -6303,9 +6303,9 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6303
6303
  ns.unshift(new parser_1.Node('('));
6304
6304
  ns.push(new parser_1.Node(')'));
6305
6305
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6306
- class: 'bracket'
6306
+ class: (0, bracket_1.bracketname)(context, 1, 1)
6307
6307
  }, ['(', (0, dom_1.html)('span', {
6308
- class: 'bracket'
6308
+ class: (0, bracket_1.bracketname)(context, 2, 2)
6309
6309
  }, (0, dom_1.defrag)((0, util_1.unwrap)(ns))), ')']))]);
6310
6310
  }
6311
6311
  const depth = MAX_DEPTH - (resources?.recursions[4 /* Recursion.annotation */] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
@@ -6344,7 +6344,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6344
6344
  context.position += 1;
6345
6345
  recursion.add(depth);
6346
6346
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6347
- class: 'bracket'
6347
+ class: 'paren'
6348
6348
  }, ['(', (0, dom_1.html)('sup', {
6349
6349
  class: 'annotation'
6350
6350
  }, [(0, dom_1.html)('span', bs.head.value.childNodes)])]))]);
@@ -6353,7 +6353,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6353
6353
  context.position += 1;
6354
6354
  recursion.add(depth);
6355
6355
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6356
- class: 'bracket'
6356
+ class: 'paren'
6357
6357
  }, ['(', (0, dom_1.html)('sup', {
6358
6358
  class: 'annotation'
6359
6359
  }, [(0, dom_1.html)('span', [bs.head.value])])]))]);
@@ -6367,7 +6367,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6367
6367
  context.range += 1;
6368
6368
  }
6369
6369
  bs = new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6370
- class: (0, bracket_1.bracketname)(context, bracket_1.indexA, 2, context.position - position)
6370
+ class: (0, bracket_1.bracketname)(context, 2, context.position - position)
6371
6371
  }, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]);
6372
6372
  bs.unshift(new parser_1.Node('('));
6373
6373
  const cs = parser(context);
@@ -6375,9 +6375,10 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6375
6375
  cs && bs.import(cs);
6376
6376
  bs.push(new parser_1.Node(')'));
6377
6377
  context.position += 1;
6378
+ context.range += 1;
6378
6379
  }
6379
6380
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6380
- class: 'bracket'
6381
+ class: (0, bracket_1.bracketname)(context, 1, context.position - position)
6381
6382
  }, (0, dom_1.defrag)((0, util_1.unwrap)(bs))))]);
6382
6383
  })));
6383
6384
  const parser = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(1, (0, combinator_1.some)(inline_1.inline, ')', [[')', 1]])));
@@ -6664,7 +6665,7 @@ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combin
6664
6665
  Object.defineProperty(exports, "__esModule", ({
6665
6666
  value: true
6666
6667
  }));
6667
- exports.bracket = exports.bracketname = exports.indexA = void 0;
6668
+ exports.bracket = exports.bracketname = void 0;
6668
6669
  const parser_1 = __webpack_require__(605);
6669
6670
  const combinator_1 = __webpack_require__(3484);
6670
6671
  const inline_1 = __webpack_require__(7973);
@@ -6672,17 +6673,12 @@ const link_1 = __webpack_require__(3628);
6672
6673
  const source_1 = __webpack_require__(8745);
6673
6674
  const util_1 = __webpack_require__(4992);
6674
6675
  const dom_1 = __webpack_require__(394);
6675
- exports.indexA = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*$/;
6676
- const indexF = new RegExp(exports.indexA.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => String.fromCodePoint(c.codePointAt(0) + 0xFEE0)), '');
6677
- function bracketname(context, syntax, opener, closer) {
6676
+ function bracketname(context, opener, closer) {
6678
6677
  const {
6679
- source,
6680
- position,
6681
6678
  range,
6682
6679
  linebreak
6683
6680
  } = context;
6684
- syntax.lastIndex = position - range + opener;
6685
- return range - opener - closer === 0 || linebreak === 0 && range - opener - closer <= 16 && syntax.test(source.slice(position - range + opener, position - closer)) ? 'paren' : 'bracket';
6681
+ return range - opener - closer === 0 || linebreak === 0 && range - opener - closer <= 16 ? 'paren' : 'bracket';
6686
6682
  }
6687
6683
  exports.bracketname = bracketname;
6688
6684
  exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([input => {
@@ -6708,14 +6704,14 @@ exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([input =>
6708
6704
  }
6709
6705
  }]));
6710
6706
  const p1 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(5 /* Recursion.bracket */, (0, combinator_1.some)(inline_1.inline, ')', [[')', 1]]))), (0, source_1.str)(')'), true, [], ([as, bs = new parser_1.List(), cs], context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6711
- class: bracketname(context, exports.indexA, 1, 1)
6707
+ class: bracketname(context, 1, 1)
6712
6708
  }, (0, dom_1.defrag)((0, util_1.unwrap)(as.import(bs).import(cs)))))]), ([as, bs = new parser_1.List()], context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6713
- class: bracketname(context, exports.indexA, 1, 0)
6709
+ class: bracketname(context, 1, 0)
6714
6710
  }, (0, dom_1.defrag)((0, util_1.unwrap)(as.import(bs)))))])));
6715
6711
  const p2 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(5 /* Recursion.bracket */, (0, combinator_1.some)(inline_1.inline, ')', [[')', 1]]))), (0, source_1.str)(')'), true, [], ([as, bs = new parser_1.List(), cs], context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6716
- class: bracketname(context, indexF, 1, 1)
6712
+ class: bracketname(context, 1, 1)
6717
6713
  }, (0, dom_1.defrag)((0, util_1.unwrap)(as.import(bs).import(cs)))))]), ([as, bs = new parser_1.List()], context) => new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6718
- class: bracketname(context, indexF, 1, 0)
6714
+ class: bracketname(context, 1, 0)
6719
6715
  }, (0, dom_1.defrag)((0, util_1.unwrap)(as.import(bs)))))])));
6720
6716
  const s1 = (0, combinator_1.lazy)(() => (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(5 /* Recursion.bracket */, (0, combinator_1.some)(inline_1.inline, ']', [[']', 1]]))), (0, source_1.str)(']'), true, [2 | 4 /* Backtrack.common */], ([as, bs = new parser_1.List(), cs], context) => {
6721
6717
  const {
@@ -8419,7 +8415,7 @@ function* proc(note, defs) {
8419
8415
  Object.defineProperty(exports, "__esModule", ({
8420
8416
  value: true
8421
8417
  }));
8422
- exports.validate = exports.segment = exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE = void 0;
8418
+ exports.segment = void 0;
8423
8419
  const context_1 = __webpack_require__(8669);
8424
8420
  const combinator_1 = __webpack_require__(3484);
8425
8421
  const heading_1 = __webpack_require__(2778);
@@ -8428,9 +8424,7 @@ const mathblock_1 = __webpack_require__(4903);
8428
8424
  const extension_1 = __webpack_require__(6193);
8429
8425
  const source_1 = __webpack_require__(8745);
8430
8426
  const api_1 = __webpack_require__(5886);
8431
- exports.MAX_SEGMENT_SIZE = 100_000; // 100,000 bytes (Max value size of FDB)
8432
- exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE * 10;
8433
- const parser = (0, combinator_1.union)([(0, combinator_1.some)(source_1.emptysegment, exports.MAX_SEGMENT_SIZE + 1), input => {
8427
+ const parser = (0, combinator_1.union)([(0, combinator_1.some)(source_1.emptysegment, context_1.MAX_SEGMENT_SIZE + 1), input => {
8434
8428
  const {
8435
8429
  source,
8436
8430
  position
@@ -8452,22 +8446,22 @@ const parser = (0, combinator_1.union)([(0, combinator_1.some)(source_1.emptyseg
8452
8446
  case '#':
8453
8447
  return (0, heading_1.segment)(input);
8454
8448
  }
8455
- }, (0, combinator_1.some)(source_1.contentline, exports.MAX_SEGMENT_SIZE + 1)]);
8449
+ }, (0, combinator_1.some)(source_1.contentline, context_1.MAX_SEGMENT_SIZE + 1)]);
8456
8450
  function* segment(source, initial = true) {
8457
- if (initial && !validate(source, exports.MAX_INPUT_SIZE)) return yield [`${"\u0007" /* Command.Error */}Too large input over ${exports.MAX_INPUT_SIZE.toLocaleString('en')} bytes.\n${source.slice(0, 1001)}`, 0 /* Segment.unknown */];
8458
- for (let position = 0; position < source.length;) {
8451
+ if (initial && !validate(source, context_1.MAX_INPUT_SIZE)) return yield [`${"\u0007" /* Command.Error */}Too large input over ${context_1.MAX_INPUT_SIZE.toLocaleString('en')} bytes.\n${source.slice(0, 1001)}`, 0 /* Segment.unknown */];
8452
+ for (let position = 0, len = source.length; position < len;) {
8459
8453
  const context = new context_1.Context({
8460
8454
  source,
8461
8455
  position
8462
8456
  });
8463
8457
  const result = parser(context);
8464
- const segs = result.length > 0 ? result.foldl((acc, {
8458
+ const segs = result.length === 0 ? [source.slice(position, context.position)] : result.foldl((acc, {
8465
8459
  value
8466
- }) => void acc.push(value) || acc, []) : [source.slice(position, context.position)];
8460
+ }) => (acc.push(value), acc), []);
8467
8461
  position = context.position;
8468
8462
  for (let i = 0; i < segs.length; ++i) {
8469
8463
  const seg = segs[i];
8470
- initial && !validate(seg, exports.MAX_SEGMENT_SIZE) ? yield [`${"\u0007" /* Command.Error */}Too large segment over ${exports.MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.\n${seg}`, 0 /* Segment.unknown */] : yield [initial ? (0, api_1.normalize)(seg) : seg, context.segment];
8464
+ initial && !validate(seg, context_1.MAX_SEGMENT_SIZE) ? yield [`${"\u0007" /* Command.Error */}Too large segment over ${context_1.MAX_SEGMENT_SIZE.toLocaleString('en')} bytes.\n${seg}`, 0 /* Segment.unknown */] : yield [initial ? (0, api_1.normalize)(seg) : seg, context.segment];
8471
8465
  }
8472
8466
  }
8473
8467
  }
@@ -8475,7 +8469,6 @@ exports.segment = segment;
8475
8469
  function validate(source, size) {
8476
8470
  return source.length <= size / 2 || source.length <= size && new Blob([source]).size <= size;
8477
8471
  }
8478
- exports.validate = validate;
8479
8472
 
8480
8473
  /***/ },
8481
8474
 
@@ -9098,7 +9091,6 @@ function repeat(symbol, after, parser, cons, termination = (nodes, context, pref
9098
9091
  }
9099
9092
  break;
9100
9093
  }
9101
- if (nodes.length === 0) return;
9102
9094
  const prefix = i;
9103
9095
  i = 0;
9104
9096
  for (let len = (0, alias_1.min)(prefix, source.length - context.position); i < len && source[context.position + i] === symbol[0];) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.298.3",
3
+ "version": "0.298.5",
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,5 @@
1
1
  import { ParserSettings, Progress } from '../../..';
2
- import { Context, Segment } from '../context';
2
+ import { Context, Options, Segment } from '../context';
3
3
  import { input } from '../../combinator/data/parser';
4
4
  import { segment } from '../segment';
5
5
  import { block } from '../block';
@@ -17,15 +17,12 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
17
17
  nearest: (position: number) => HTMLElement | undefined;
18
18
  index: (block: HTMLElement) => number;
19
19
  } {
20
- const context = new Context({
20
+ const options: Options = {
21
21
  ...settings,
22
22
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
23
- });
24
- assert(!context.offset);
25
- assert(!context.precedence);
26
- assert(!context.state);
27
- if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
28
- if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
23
+ };
24
+ if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
25
+ if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
29
26
  type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
30
27
  const blocks: Block[] = [];
31
28
  const adds: (readonly [HTMLElement, Node | null])[] = [];
@@ -42,11 +39,11 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
42
39
  if (settings.chunk && revision) throw new Error('Chunks cannot be updated');
43
40
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
44
41
  // @ts-expect-error
45
- context.url = url ? new ReadonlyURL(url as ':') : undefined;
42
+ options.url = url ? new ReadonlyURL(url as ':') : undefined;
46
43
  const rev = revision = Symbol();
47
44
  const sourceSegments: string[] = [];
48
45
  const sourceSegmentAttrs: Segment[] = [];
49
- for (const [seg, attr] of segment(source, !context.local)) {
46
+ for (const [seg, attr] of segment(source, true)) {
50
47
  sourceSegments.push(seg);
51
48
  sourceSegmentAttrs.push(attr);
52
49
  yield { type: 'segment', value: seg };
@@ -71,15 +68,15 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
71
68
  const base = next(head);
72
69
  let index = head;
73
70
  // @ts-expect-error
74
- context.header = true;
71
+ options.header = true;
75
72
  for (; index < sourceSegments.length - last; ++index) {
76
73
  assert(rev === revision);
77
74
  const seg = sourceSegments[index];
78
- context.segment = sourceSegmentAttrs[index] | Segment.write;
79
- const es = block(input(seg, new Context(context)))!
75
+ options.segment = sourceSegmentAttrs[index] | Segment.write;
76
+ const es = block(input(seg, new Context(options)))!
80
77
  .foldl<HTMLElement[]>((acc, { value }) => void acc.push(value) || acc, []);
81
78
  // @ts-expect-error
82
- context.header = false;
79
+ options.header = false;
83
80
  blocks.length === index
84
81
  ? blocks.push([seg, es, url])
85
82
  : blocks.splice(index, 0, [seg, es, url]);
@@ -124,14 +121,14 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
124
121
  }
125
122
  yield { type: 'break' };
126
123
  if (rev !== revision) return yield { type: 'cancel' };
127
- for (const el of figure(next(0)?.parentNode ?? target, settings.notes, context)) {
124
+ for (const el of figure(next(0)?.parentNode ?? target, settings.notes, options)) {
128
125
  assert(rev === revision);
129
126
  el
130
127
  ? yield { type: 'figure', value: el }
131
128
  : yield { type: 'break' };
132
129
  if (rev !== revision) return yield { type: 'cancel' };
133
130
  }
134
- for (const el of note(next(0)?.parentNode ?? target, settings.notes, context, bottom)) {
131
+ for (const el of note(next(0)?.parentNode ?? target, settings.notes, options, bottom)) {
135
132
  assert(rev === revision);
136
133
  el
137
134
  ? yield { type: 'note', value: el }
@@ -306,15 +306,6 @@ describe('Unit: parser/api/parse', () => {
306
306
  // '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
307
307
  // `<pre class="error" translate="no">${'{ '.repeat(21)}0</pre>`,
308
308
  // ]);
309
- assert.deepStrictEqual(
310
- [...parse(`${'('.repeat(20)}0`).children].map(el => el.outerHTML),
311
- [`<p>${'<span class="bracket">('.repeat(19)}<span class="paren">(0</span>${'</span>'.repeat(19)}</p>`]);
312
- assert.deepStrictEqual(
313
- [...parse(`${'('.repeat(21)}0`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
314
- [
315
- '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
316
- `<pre class="error" translate="no">${'('.repeat(21)}0</pre>`,
317
- ]);
318
309
  assert.deepStrictEqual(
319
310
  [...parse(`${'['.repeat(20)}0`).children].map(el => el.outerHTML),
320
311
  [`<p>${'['.repeat(20)}0</p>`]);
@@ -324,6 +315,12 @@ describe('Unit: parser/api/parse', () => {
324
315
  '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
325
316
  `<pre class="error" translate="no">${'['.repeat(21)}0</pre>`,
326
317
  ]);
318
+ assert.deepStrictEqual(
319
+ [...parse(`${'('.repeat(20)}0`).children].map(el => el.tagName),
320
+ ['P']);
321
+ assert.deepStrictEqual(
322
+ [...parse(`${'('.repeat(21)}0`).children].map(el => el.tagName),
323
+ ['H1', 'PRE']);
327
324
  assert.deepStrictEqual(
328
325
  [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
329
326
  ['P', 'OL']);
@@ -398,7 +395,7 @@ describe('Unit: parser/api/parse', () => {
398
395
  });
399
396
 
400
397
  it('backtrack 1', () => {
401
- // 最悪計算量での実行速度はCommonMarkの公式JS実装の32nに対して50-400%程度。
398
+ // 最悪計算量での実行速度はCommonMarkの公式JS実装の32nに対して1-4倍程度。
402
399
  // 5n = reference + link + url/math + ruby + text
403
400
  assert.deepStrictEqual(
404
401
  [...parse(`((([[[[#$[${'.'.repeat(19998)}`, {}, new Context({ resources: { clock: 100000, recursions: [100] } })).children]
@@ -1,6 +1,6 @@
1
1
  import { ParserOptions } from '../../..';
2
2
  import { input } from '../../combinator/data/parser';
3
- import { Context, Segment } from '../context';
3
+ import { Context, Options, Segment } from '../context';
4
4
  import { segment } from '../segment';
5
5
  import { block } from '../block';
6
6
  import { headers } from './header';
@@ -9,43 +9,40 @@ import { note } from '../processor/note';
9
9
  import { ReadonlyURL } from 'spica/url';
10
10
  import { frag } from 'typed-dom/dom';
11
11
 
12
- interface Options extends ParserOptions {
12
+ interface Opts extends ParserOptions {
13
13
  readonly local?: boolean;
14
14
  readonly test?: boolean;
15
15
  }
16
16
 
17
- export function parse(source: string, options: Options = {}, context?: Context): DocumentFragment {
17
+ export function parse(source: string, opts: Opts = {}, options?: Options): DocumentFragment {
18
18
  const url = headers(source).find(field => field.toLowerCase().startsWith('url:'))?.slice(4).trim() ?? '';
19
- context = new Context({
20
- host: options.host ?? context?.host ?? new ReadonlyURL(location.pathname, location.origin),
21
- url: url ? new ReadonlyURL(url as ':') : context?.url,
22
- id: options.id ?? context?.id,
23
- local: options.local ?? context?.local,
24
- caches: context?.caches,
25
- resources: context?.resources,
26
- });
27
- assert(!context.offset);
28
- assert(!context.precedence);
29
- assert(!context.state);
30
- if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
31
- if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
19
+ options = {
20
+ host: opts.host ?? options?.host ?? new ReadonlyURL(location.pathname, location.origin),
21
+ url: url ? new ReadonlyURL(url as ':') : options?.url,
22
+ id: opts.id ?? options?.id,
23
+ local: opts.local ?? options?.local ?? false,
24
+ caches: options?.caches,
25
+ resources: options?.resources,
26
+ };
27
+ if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
28
+ if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
32
29
  const node = frag();
33
30
  // @ts-expect-error
34
- context.header = true;
35
- for (const [seg, attr] of segment(source, !context.local)) {
36
- context.segment = attr | Segment.write;
37
- const es = block(input(seg, new Context(context)))!
31
+ options.header = true;
32
+ for (const [seg, attr] of segment(source, !options.local)) {
33
+ options.segment = attr | Segment.write;
34
+ const es = block(input(seg, new Context(options)))!
38
35
  .foldl<HTMLElement[]>((acc, { value }) => void acc.push(value) || acc, [])
39
36
  // @ts-expect-error
40
- context.header = false;
37
+ options.header = false;
41
38
  if (es.length === 0) continue;
42
39
  node.append(...es);
43
40
  }
44
- assert(options.id !== '' || !node.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
45
- if (options.test) return node;
46
- for (const _ of figure(node, options.notes, context));
47
- for (const _ of note(node, options.notes, context));
48
- assert(options.id !== '' || !node.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
49
- assert(options.id !== '' || !options.notes?.references.querySelector('[id], .index[href], .label[href]'));
41
+ assert(opts.id !== '' || !node.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
42
+ if (opts.test) return node;
43
+ for (const _ of figure(node, opts.notes, options));
44
+ for (const _ of note(node, opts.notes, options));
45
+ assert(opts.id !== '' || !node.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
46
+ assert(opts.id !== '' || !opts.notes?.references.querySelector('[id], .index[href], .label[href]'));
50
47
  return node;
51
48
  }
@@ -44,8 +44,8 @@ describe('Unit: parser/block/heading', () => {
44
44
  assert.deepStrictEqual(inspect(parser, input('## http://host', new Context())), [['<h2 id="index::http://host"><a class="url" href="http://host" target="_blank">http://host</a></h2>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser, input('# !http://host', new Context())), [['<h1 id="index::!http://host">!http://host</h1>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser, input('## !http://host', new Context())), [['<h2 id="index::!http://host">!<a class="url" href="http://host" target="_blank">http://host</a></h2>'], '']);
47
- assert.deepStrictEqual(inspect(parser, input('# a((b))', new Context())), [['<h1 id="index::a((b))">a<span class="bracket">(<span class="paren">(b)</span>)</span></h1>'], '']);
48
- assert.deepStrictEqual(inspect(parser, input('## a((b))', new Context())), [['<h2 id="index::a((b))">a<span class="bracket">(<span class="paren">(b)</span>)</span></h2>'], '']);
47
+ assert.deepStrictEqual(inspect(parser, input('# a((b))', new Context())), [['<h1 id="index::a((b))">a<span class="paren">(<span class="paren">(b)</span>)</span></h1>'], '']);
48
+ assert.deepStrictEqual(inspect(parser, input('## a((b))', new Context())), [['<h2 id="index::a((b))">a<span class="paren">(<span class="paren">(b)</span>)</span></h2>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser, input('# a[[b]]', new Context())), [['<h1 id="index::a[[b]]">a[[b]]</h1>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser, input('## a[[b]]', new Context())), [['<h2 id="index::a[[b]]">a[[b]]</h2>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser, input('###### a', new Context())), [['<h6 id="index::a">a</h6>'], '']);
@@ -33,7 +33,7 @@ describe('Unit: parser/block/table', () => {
33
33
  assert.deepStrictEqual(inspect(parser, input('|||\n|-|-|\n|||', new Context())), [['<table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td></td><td></td></tr></tbody></table>'], '']);
34
34
  assert.deepStrictEqual(inspect(parser, input('|"|\n|-\n|', new Context())), [['<table><thead><tr><th>"</th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser, input('|`|`|\n|-\n|', new Context())), [['<table><thead><tr><th><code data-src="`|`">|</code></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
36
- assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="bracket">(<span class="paren">(</span></span></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
36
+ assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="paren">(<span class="paren">(</span></span></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser, input('|a|b|\n|-|-|\n|1|2|', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
38
38
  assert.deepStrictEqual(inspect(parser, input('|a|b\n|-|-\n|1|2', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser, input('|a|\n|-|\n|1|', new Context())), [['<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>'], '']);