securemark 0.281.2 → 0.281.4

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.281.4
4
+
5
+ - Fix identifiers.
6
+
7
+ ## 0.281.3
8
+
9
+ - Refactoring.
10
+
3
11
  ## 0.281.2
4
12
 
5
13
  - Fix identifiers.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.281.2 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.281.4 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"));
@@ -3169,6 +3169,7 @@ function context(base, parser) {
3169
3169
  }
3170
3170
  exports.context = context;
3171
3171
  function apply(parser, source, context, changes, values, reset = false) {
3172
+ reset && context.memo?.clear();
3172
3173
  for (let i = 0; i < changes.length; ++i) {
3173
3174
  const change = changes[i];
3174
3175
  const prop = change[0];
@@ -3190,9 +3191,6 @@ function apply(parser, source, context, changes, values, reset = false) {
3190
3191
  switch (prop) {
3191
3192
  case 'resources':
3192
3193
  break;
3193
- case 'memo':
3194
- context.memo.clear();
3195
- break;
3196
3194
  }
3197
3195
  context[prop] = values[i];
3198
3196
  values[i] = undefined;
@@ -3441,7 +3439,7 @@ Delimiters.matcher = (0, memoize_1.memoize)(pattern => {
3441
3439
  /***/ }),
3442
3440
 
3443
3441
  /***/ 1074:
3444
- /***/ ((__unused_webpack_module, exports) => {
3442
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
3445
3443
 
3446
3444
  "use strict";
3447
3445
 
@@ -3450,15 +3448,17 @@ Object.defineProperty(exports, "__esModule", ({
3450
3448
  value: true
3451
3449
  }));
3452
3450
  exports.Memo = void 0;
3451
+ const alias_1 = __webpack_require__(5413);
3453
3452
  class Memo {
3454
3453
  constructor(targets = ~0, margin = 0) {
3455
3454
  this.targets = targets;
3456
3455
  this.margin = margin;
3457
- this.memory = [];
3456
+ this.memory = {};
3458
3457
  this.count = 0;
3458
+ this.$length = 0;
3459
3459
  }
3460
3460
  get length() {
3461
- return this.memory.length;
3461
+ return this.$length;
3462
3462
  }
3463
3463
  get(position, syntax, state) {
3464
3464
  if (this.count === 0) return;
@@ -3467,21 +3467,23 @@ class Memo {
3467
3467
  return cache?.length === 2 ? [cache[0].slice(), cache[1]] : cache;
3468
3468
  }
3469
3469
  set(position, syntax, state, nodes, offset) {
3470
- this.count += +!this.memory[position - 1];
3471
- const record = this.memory[position - 1] ??= {};
3470
+ this.$length = (0, alias_1.max)(this.$length, position);
3471
+ const record = this.memory[position - 1] ??= (++this.count, {});
3472
3472
  (record[syntax] ??= {})[state] = nodes ? [nodes.slice(), offset] : [];
3473
3473
  //console.log('set', position, syntax, state, record[syntax]?.[state]);
3474
3474
  }
3475
3475
  resize(position) {
3476
3476
  const memory = this.memory;
3477
- for (let i = memory.length; i > position; --i) {
3478
- this.count -= +memory.pop();
3477
+ for (let i = this.$length; i > position; this.$length = --i) {
3478
+ if (!(i in memory)) continue;
3479
+ memory[i] &&= (--this.count, undefined);
3479
3480
  }
3480
3481
  //console.log('resize', position + 1);
3481
3482
  }
3482
3483
  clear() {
3483
- this.memory = [];
3484
+ this.memory = {};
3484
3485
  this.count = 0;
3486
+ this.$length = 0;
3485
3487
  }
3486
3488
  }
3487
3489
  exports.Memo = Memo;
@@ -3787,6 +3789,8 @@ Object.defineProperty(exports, "__esModule", ({
3787
3789
  }));
3788
3790
  exports.bind = void 0;
3789
3791
  const parser_1 = __webpack_require__(605);
3792
+ const memo_1 = __webpack_require__(1074);
3793
+ const context_1 = __webpack_require__(8669);
3790
3794
  const segment_1 = __webpack_require__(3967);
3791
3795
  const header_1 = __webpack_require__(3009);
3792
3796
  const block_1 = __webpack_require__(7099);
@@ -3799,7 +3803,8 @@ const array_1 = __webpack_require__(6876);
3799
3803
  function bind(target, settings) {
3800
3804
  let context = {
3801
3805
  ...settings,
3802
- host: settings.host ?? new url_1.ReadonlyURL(location.pathname, location.origin)
3806
+ host: settings.host ?? new url_1.ReadonlyURL(location.pathname, location.origin),
3807
+ memo: new memo_1.Memo(508 /* Syntax.targets */, context_1.Margin)
3803
3808
  };
3804
3809
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
3805
3810
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
@@ -4124,6 +4129,8 @@ Object.defineProperty(exports, "__esModule", ({
4124
4129
  }));
4125
4130
  exports.parse = void 0;
4126
4131
  const parser_1 = __webpack_require__(605);
4132
+ const memo_1 = __webpack_require__(1074);
4133
+ const context_1 = __webpack_require__(8669);
4127
4134
  const segment_1 = __webpack_require__(3967);
4128
4135
  const header_1 = __webpack_require__(3009);
4129
4136
  const block_1 = __webpack_require__(7099);
@@ -4142,7 +4149,8 @@ function parse(source, opts = {}, context) {
4142
4149
  url: url ? new url_1.ReadonlyURL(url) : context?.url,
4143
4150
  id: opts.id ?? context?.id,
4144
4151
  caches: context?.caches,
4145
- resources: context?.resources
4152
+ resources: context?.resources,
4153
+ memo: new memo_1.Memo(508 /* Syntax.targets */, context_1.Margin)
4146
4154
  };
4147
4155
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
4148
4156
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
@@ -4196,7 +4204,6 @@ Object.defineProperty(exports, "__esModule", ({
4196
4204
  }));
4197
4205
  exports.block = void 0;
4198
4206
  const combinator_1 = __webpack_require__(3484);
4199
- const memo_1 = __webpack_require__(1074);
4200
4207
  const source_1 = __webpack_require__(8745);
4201
4208
  const pagebreak_1 = __webpack_require__(2946);
4202
4209
  const heading_1 = __webpack_require__(2778);
@@ -4219,8 +4226,7 @@ exports.block = (0, combinator_1.creation)(0, false, (0, combinator_1.reset)({
4219
4226
  resources: {
4220
4227
  clock: 20000,
4221
4228
  recursion: 20 + 1
4222
- },
4223
- memo: new memo_1.Memo(508 /* Syntax.targets */, 2)
4229
+ }
4224
4230
  }, error((0, combinator_1.union)([source_1.emptyline, pagebreak_1.pagebreak, heading_1.heading, ulist_1.ulist, olist_1.olist, ilist_1.ilist, dlist_1.dlist, table_1.table, codeblock_1.codeblock, mathblock_1.mathblock, extension_1.extension, sidefence_1.sidefence, blockquote_1.blockquote, mediablock_1.mediablock, reply_1.reply, paragraph_1.paragraph]))));
4225
4231
  function error(parser) {
4226
4232
  return (0, combinator_1.recover)((0, combinator_1.fallback)((0, combinator_1.open)('\x07', ({
@@ -5552,6 +5558,20 @@ function format(list) {
5552
5558
 
5553
5559
  /***/ }),
5554
5560
 
5561
+ /***/ 8669:
5562
+ /***/ ((__unused_webpack_module, exports) => {
5563
+
5564
+ "use strict";
5565
+
5566
+
5567
+ Object.defineProperty(exports, "__esModule", ({
5568
+ value: true
5569
+ }));
5570
+ exports.Margin = void 0;
5571
+ exports.Margin = 2;
5572
+
5573
+ /***/ }),
5574
+
5555
5575
  /***/ 3009:
5556
5576
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
5557
5577
 
@@ -6100,7 +6120,7 @@ function identity(type, id, text) {
6100
6120
  const str = text.replace(/\s/g, '_');
6101
6121
  const cs = [...str];
6102
6122
  if (type === '' || cs.length <= MAX) {
6103
- return `${type}:${id ?? ''}:${str}${/_|[^\S ]/.test(text) ? `=${hash(text)}` : ''}`;
6123
+ return `${type}:${id ?? ''}:${str}${/_|[^\S ]|=[0-9a-z]{1,7}$/.test(text) ? `=${hash(text)}` : ''}`;
6104
6124
  }
6105
6125
  const s1 = cs.slice(0, PART + REM).join('');
6106
6126
  const s2 = cs.slice(-PART).join('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.281.2",
3
+ "version": "0.281.4",
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,19 +1,22 @@
1
+ import { max } from 'spica/alias';
2
+
1
3
  export class Memo {
2
4
  constructor(
3
5
  public readonly targets = ~0,
4
6
  public readonly margin = 0,
5
7
  ) {
6
8
  }
7
- private memory: Record<number, Record<number, readonly [any[], number] | readonly []>>[/* pos */] = [];
9
+ private memory: Record<number, Record<number, Record<number, readonly [unknown[], number] | readonly []>> | undefined> = {};
8
10
  private count = 0;
11
+ private $length = 0;
9
12
  public get length(): number {
10
- return this.memory.length;
13
+ return this.$length;
11
14
  }
12
15
  public get(
13
16
  position: number,
14
17
  syntax: number,
15
18
  state: number,
16
- ): readonly [any[], number] | readonly [] | undefined {
19
+ ): readonly [unknown[], number] | readonly [] | undefined {
17
20
  assert(position > 0);
18
21
  if (this.count === 0) return;
19
22
  //console.log('get', position, syntax, state, this.memory[position - 1]?.[syntax]?.[state]);
@@ -26,12 +29,12 @@ export class Memo {
26
29
  position: number,
27
30
  syntax: number,
28
31
  state: number,
29
- nodes: any[] | undefined,
32
+ nodes: unknown[] | undefined,
30
33
  offset: number,
31
34
  ): void {
32
35
  assert(position > 0);
33
- this.count += +!this.memory[position - 1];
34
- const record = this.memory[position - 1] ??= {};
36
+ this.$length = max(this.$length, position);
37
+ const record = this.memory[position - 1] ??= (++this.count, {});
35
38
  assert(!record[syntax]?.[state]);
36
39
  (record[syntax] ??= {})[state] = nodes
37
40
  ? [nodes.slice(), offset]
@@ -40,13 +43,15 @@ export class Memo {
40
43
  }
41
44
  public resize(position: number): void {
42
45
  const memory = this.memory;
43
- for (let i = memory.length; i > position; --i) {
44
- this.count -= +memory.pop()!;
46
+ for (let i = this.$length; i > position; this.$length = --i) {
47
+ if (!(i in memory)) continue;
48
+ memory[i] &&= (--this.count, undefined);
45
49
  }
46
50
  //console.log('resize', position + 1);
47
51
  }
48
52
  public clear(): void {
49
- this.memory = [];
53
+ this.memory = {};
50
54
  this.count = 0;
55
+ this.$length = 0;
51
56
  }
52
57
  }
@@ -24,6 +24,7 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
24
24
 
25
25
  function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Tree<P>>;
26
26
  function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<T> {
27
+ reset && context.memo?.clear();
27
28
  for (let i = 0; i < changes.length; ++i) {
28
29
  const change = changes[i];
29
30
  const prop = change[0];
@@ -34,7 +35,6 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
34
35
  assert(!context.precedence);
35
36
  assert(!context.delimiters);
36
37
  assert(!context.state);
37
- assert(!context.memo);
38
38
  context[prop as string] ??= ObjectCreate(change[1] as object);
39
39
  continue;
40
40
  }
@@ -49,10 +49,6 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
49
49
  case 'resources':
50
50
  assert(reset);
51
51
  break;
52
- case 'memo':
53
- assert(reset);
54
- context.memo!.clear();
55
- break;
56
52
  }
57
53
  context[prop] = values[i];
58
54
  values[i] = undefined;
@@ -61,7 +57,7 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: read
61
57
  }
62
58
 
63
59
  export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number, state: number, parser: P): P;
64
- export function syntax<T>(syntax: number, prec: number, state: number, parser?: Parser<T>): Parser<T> {
60
+ export function syntax<T>(syntax: number, prec: number, state: number, parser: Parser<T>): Parser<T> {
65
61
  return precedence(prec, ({ source, context }) => {
66
62
  if (source === '') return;
67
63
  const memo = context.memo ??= new Memo();
@@ -73,12 +69,12 @@ export function syntax<T>(syntax: number, prec: number, state: number, parser?:
73
69
  const result: Result<T> = cache
74
70
  ? cache.length === 0
75
71
  ? undefined
76
- : [cache[0], source.slice(cache[1])]
77
- : parser!({ source, context });
72
+ : [cache[0] as T[], source.slice(cache[1])]
73
+ : parser({ source, context });
78
74
  if (stateOuter && !cache && syntax & memo.targets) {
79
75
  memo.set(position, syntax, stateInner, eval(result), source.length - exec(result, '').length);
80
76
  }
81
- else if (!stateOuter && result && memo.length! >= position + memo.margin) {
77
+ else if (!stateOuter && result && memo.length >= position + memo.margin) {
82
78
  memo.resize(position + memo.margin);
83
79
  }
84
80
  context.state = stateOuter;
@@ -1,6 +1,8 @@
1
1
  import { ParserSettings, Progress } from '../../..';
2
2
  import { MarkdownParser } from '../../../markdown';
3
3
  import { eval } from '../../combinator/data/parser';
4
+ import { Memo } from '../../combinator/data/parser/context/memo';
5
+ import { Syntax, Margin } from '../context';
4
6
  import { segment, validate, MAX_INPUT_SIZE } from '../segment';
5
7
  import { header } from '../header';
6
8
  import { block } from '../block';
@@ -22,12 +24,12 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
22
24
  let context: MarkdownParser.Context = {
23
25
  ...settings,
24
26
  host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
27
+ memo: new Memo(Syntax.targets, Margin),
25
28
  };
26
29
  assert(!context.offset);
27
30
  assert(!context.precedence);
28
31
  assert(!context.delimiters);
29
32
  assert(!context.state);
30
- assert(!context.memo);
31
33
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
32
34
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
33
35
  type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
@@ -1,6 +1,8 @@
1
1
  import { ParserOptions } from '../../..';
2
2
  import { MarkdownParser } from '../../../markdown';
3
3
  import { eval } from '../../combinator/data/parser';
4
+ import { Memo } from '../../combinator/data/parser/context/memo';
5
+ import { Syntax, Margin } from '../context';
4
6
  import { segment, validate, MAX_SEGMENT_SIZE } from '../segment';
5
7
  import { header } from '../header';
6
8
  import { block } from '../block';
@@ -25,12 +27,12 @@ export function parse(source: string, opts: Options = {}, context?: MarkdownPars
25
27
  id: opts.id ?? context?.id,
26
28
  caches: context?.caches,
27
29
  resources: context?.resources,
30
+ memo: new Memo(Syntax.targets, Margin),
28
31
  };
29
32
  assert(!context.offset);
30
33
  assert(!context.precedence);
31
34
  assert(!context.delimiters);
32
35
  assert(!context.state);
33
- assert(!context.memo);
34
36
  if (context.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
35
37
  if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
36
38
  const node = frag();
@@ -1,6 +1,5 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
2
  import { union, reset, creation, open, fallback, recover } from '../combinator';
3
- import { Memo } from '../combinator/data/parser/context/memo';
4
3
  import { emptyline } from './source';
5
4
  import { pagebreak } from './block/pagebreak';
6
5
  import { heading } from './block/heading';
@@ -17,7 +16,6 @@ import { blockquote } from './block/blockquote';
17
16
  import { mediablock } from './block/mediablock';
18
17
  import { reply } from './block/reply';
19
18
  import { paragraph } from './block/paragraph';
20
- import { Syntax } from './context';
21
19
  import { rnd0Z } from 'spica/random';
22
20
  import { html } from 'typed-dom/dom';
23
21
 
@@ -41,7 +39,6 @@ export import ParagraphParser = BlockParser.ParagraphParser;
41
39
  export const block: BlockParser = creation(0, false,
42
40
  reset({
43
41
  resources: { clock: 20000, recursion: 20 + 1 },
44
- memo: new Memo(Syntax.targets, 2),
45
42
  },
46
43
  error(union([
47
44
  emptyline,
@@ -39,3 +39,5 @@ export const enum State {
39
39
  | State.mark
40
40
  | State.autolink,
41
41
  }
42
+
43
+ export const Margin = 2;
@@ -32,7 +32,7 @@ export function identity(
32
32
  const str = text.replace(/\s/g, '_');
33
33
  const cs = [...str];
34
34
  if (type === '' || cs.length <= MAX) {
35
- return `${type}:${id ?? ''}:${str}${/_|[^\S ]/.test(text) ? `=${hash(text)}` : ''}`;
35
+ return `${type}:${id ?? ''}:${str}${/_|[^\S ]|=[0-9a-z]{1,7}$/.test(text) ? `=${hash(text)}` : ''}`;
36
36
  }
37
37
  const s1 = cs.slice(0, PART + REM).join('');
38
38
  const s2 = cs.slice(-PART).join('');
@@ -48,6 +48,9 @@ assert.notDeepStrictEqual(
48
48
  assert.notDeepStrictEqual(
49
49
  identity('index', undefined, '0 0'),
50
50
  identity('index', undefined, '0\t0'));
51
+ assert.notDeepStrictEqual(
52
+ identity('index', undefined, '0_0'),
53
+ identity('index', undefined, identity('index', undefined, '0_0')!.slice(7).replace('_', ' ')));
51
54
  assert.deepStrictEqual(
52
55
  identity('index', undefined, `${'0'.repeat(MAX - 1)}1`)!.slice(7),
53
56
  `${'0'.repeat(MAX - 1)}1`);
@@ -30,7 +30,7 @@ describe('Unit: parser/inline/mark', () => {
30
30
 
31
31
  it('basic', () => {
32
32
  assert.deepStrictEqual(inspect(parser('==a==')), [['<mark id="mark::a">a</mark>', '<a href="#mark::a"></a>'], '']);
33
- assert.deepStrictEqual(inspect(parser('==a=b==')), [['<mark id="mark::a=b">a=b</mark>', '<a href="#mark::a=b"></a>'], '']);
33
+ assert.deepStrictEqual(inspect(parser('==a=b==')), [['<mark id="mark::a=b=1aef5x1">a=b</mark>', '<a href="#mark::a=b=1aef5x1"></a>'], '']);
34
34
  assert.deepStrictEqual(inspect(parser('==\\===')), [['<mark id="mark::=">=</mark>', '<a href="#mark::="></a>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser('==a===')), [['<mark id="mark::a">a</mark>', '<a href="#mark::a"></a>'], '=']);
36
36
  });