securemark 0.231.0 → 0.231.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.231.0",
3
+ "version": "0.231.1",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/dompurify": "2.3.3",
34
- "@types/jquery": "3.5.13",
34
+ "@types/jquery": "3.5.14",
35
35
  "@types/mathjax": "0.0.37",
36
36
  "@types/mocha": "9.1.0",
37
37
  "@types/power-assert": "1.5.8",
@@ -40,15 +40,17 @@
40
40
  "browserify-shim": "^3.8.14",
41
41
  "concurrently": "^7.0.0",
42
42
  "del": "^6.0.0",
43
+ "eslint-plugin-redos": "^4.3.0",
43
44
  "gulp": "^4.0.2",
44
45
  "gulp-derequire": "^3.0.0",
46
+ "gulp-eslint": "^6.0.0",
45
47
  "gulp-footer": "^2.1.0",
46
48
  "gulp-header": "^2.0.9",
47
49
  "gulp-load-plugins": "^2.0.7",
48
50
  "gulp-mocha": "^8.0.0",
49
51
  "gulp-rename": "^2.0.0",
50
52
  "gulp-unassert": "^2.0.0",
51
- "karma": "^6.3.16",
53
+ "karma": "^6.3.17",
52
54
  "karma-chrome-launcher": "^3.1.0",
53
55
  "karma-coverage-istanbul-instrumenter": "^1.0.4",
54
56
  "karma-coverage-istanbul-reporter": "^3.0.3",
@@ -56,13 +58,13 @@
56
58
  "karma-firefox-launcher": "^2.1.2",
57
59
  "karma-mocha": "^2.0.1",
58
60
  "mocha": "^9.2.1",
59
- "npm-check-updates": "^12.4.0",
61
+ "npm-check-updates": "^12.5.2",
60
62
  "power-assert": "^1.6.1",
61
63
  "semver": "^7.3.5",
62
- "spica": "0.0.510",
64
+ "spica": "0.0.511",
63
65
  "tsify": "^5.0.4",
64
- "typed-dom": "0.0.248",
65
- "typescript": "4.5.5",
66
+ "typed-dom": "0.0.249",
67
+ "typescript": "4.6.2",
66
68
  "vinyl-buffer": "^1.0.1",
67
69
  "vinyl-source-stream": "^2.0.0"
68
70
  },
package/src/debug.test.ts CHANGED
@@ -21,6 +21,7 @@ export function inspect(result: Result<HTMLElement | string>, until: number | st
21
21
  el.innerHTML = node.outerHTML.slice(0, until);
22
22
  if (node.outerHTML.length <= until) {
23
23
  assert(node.outerHTML === el.innerHTML);
24
+ // eslint-disable-next-line redos/no-vulnerable
24
25
  assert(node.childNodes.length === el.firstChild?.childNodes.length || />[^<]{65537}/.test(node.outerHTML));
25
26
  }
26
27
  else {
@@ -8,7 +8,7 @@ export function header(source: string): string {
8
8
 
9
9
  export function headers(source: string): string[] {
10
10
  const [el] = parse(source);
11
- return el?.textContent!.trimEnd().slice(el.firstChild!.textContent!.length).split(/[^\S\n]*\n/) ?? [];
11
+ return el?.textContent!.trimEnd().slice(el.firstChild!.textContent!.length).split('\n') ?? [];
12
12
  }
13
13
 
14
14
  function parse(source: string): [HTMLDetailsElement, string] | [] {
@@ -6,10 +6,7 @@ import { str } from '../source';
6
6
  import { html, defrag } from 'typed-dom';
7
7
  import { unshift, push } from 'spica/array';
8
8
 
9
- const index = new RegExp(`^(?:${[
10
- /(?:0|[1-9]\d*)(?:\.(?:0|[1-9]\d*))+/,
11
- /[0-9]{1,4}|[A-Za-z]/,
12
- ].map(r => r.source).join('|')})`);
9
+ const index = /^(?:[0-9]+(?:\.[0-9]+)*|[A-Za-z])/;
13
10
  const indexFW = new RegExp(index.source.replace(/[019AZaz](?!,)/g, c => String.fromCharCode(c.charCodeAt(0) + 0xfee0)));
14
11
 
15
12
  export const bracket: BracketParser = lazy(() => union([
@@ -17,8 +17,10 @@ describe('Unit: parser/inline/comment', () => {
17
17
  assert.deepStrictEqual(inspect(parser('[# #] #]')), undefined);
18
18
  assert.deepStrictEqual(inspect(parser('[# #] #]')), undefined);
19
19
  assert.deepStrictEqual(inspect(parser('[# [#')), undefined);
20
+ assert.deepStrictEqual(inspect(parser('[#[#')), undefined);
20
21
  assert.deepStrictEqual(inspect(parser('[# [# ')), undefined);
21
22
  assert.deepStrictEqual(inspect(parser('[# [# a')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('[# a[#')), [['<sup class="comment invalid">[# a</sup>'], '[#']);
22
24
  assert.deepStrictEqual(inspect(parser('[# a [#')), [['<sup class="comment invalid">[# a </sup>'], '[#']);
23
25
  assert.deepStrictEqual(inspect(parser('[# a [# ')), [['<sup class="comment invalid">[# a </sup>'], '[# ']);
24
26
  assert.deepStrictEqual(inspect(parser('[# a [#\n')), [['<sup class="comment invalid">[# a </sup>'], '[#\n']);
@@ -6,9 +6,9 @@ import { unescsource } from '../source';
6
6
  import { html } from 'typed-dom';
7
7
 
8
8
  export const comment: CommentParser = creator(validate('[#', match(
9
- /^\[(#+)\s+(?!\s|\1\]|\[\1\s)((?:\S+\s+)+?)(\1\]|(?=\[\1(?:$|\s)))/,
9
+ /^\[(#+)(?!\S|\s+\1\]|\s*\[\1(?:$|\s))((?:\s+\S+)+?)(?:\s+(\1\])|\s*(?=\[\1(?:$|\s)))/,
10
10
  ([whole, , body, closer]) => (rest, context) => {
11
- [whole, body] = `${whole}\0${body.trimEnd()}`.replace(/\x1B/g, '').split('\0', 2);
11
+ [whole, body] = `${whole}\0${body.trimStart()}`.replace(/\x1B/g, '').split('\0', 2);
12
12
  if (!closer) return [[html('sup', {
13
13
  class: 'comment invalid',
14
14
  'data-invalid-syntax': 'comment',
@@ -88,7 +88,7 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
88
88
  ])))));
89
89
 
90
90
  export const attribute: HTMLParser.TagParser.AttributeParser = union([
91
- str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\n"])*")?(?=[^\S\n]|>)/),
91
+ str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/),
92
92
  ]);
93
93
 
94
94
  function elem(tag: string, as: (HTMLElement | string)[], bs: (HTMLElement | string)[], cs: (HTMLElement | string)[], context: MarkdownParser.Context): HTMLElement {
@@ -71,7 +71,7 @@ export const uri: LinkParser.ParameterParser.UriParser = union([
71
71
 
72
72
  export const option: LinkParser.ParameterParser.OptionParser = union([
73
73
  fmap(str(/^[^\S\n]+nofollow(?=[^\S\n]|})/), () => [` rel="nofollow"`]),
74
- str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\n"])*")?(?=[^\S\n]|})/),
74
+ str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|})/),
75
75
  fmap(str(/^[^\S\n]+(?=})/), () => []),
76
76
  fmap(str(/^[^\S\n]+[^\n{}]+/), opt => [` \\${opt.slice(1)}`]),
77
77
  ]);
@@ -11,8 +11,8 @@ import { unshift, push, join } from 'spica/array';
11
11
  export const ruby: RubyParser = lazy(() => creator(bind(verify(
12
12
  validate('[', ')', '\n',
13
13
  sequence([
14
- surround('[', focus(/^(?:\\[^\n]|[^\[\]\n])+(?=]\()/, text), ']'),
15
- surround('(', focus(/^(?:\\[^\n]|[^\(\)\n])+(?=\))/, text), ')'),
14
+ surround('[', focus(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'),
15
+ surround('(', focus(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')'),
16
16
  ])),
17
17
  ([texts]) => isStartTightNodes(texts)),
18
18
  ([texts, rubies], rest) => {
@@ -42,13 +42,13 @@ const invisibleHTMLEntityNames = [
42
42
  'InvisibleComma',
43
43
  'ic',
44
44
  ];
45
- const blankline = new RegExp(String.raw`^(?!$|\n)(?:\\?\s|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>|\[(#+)\s+(?!\s|\1\]|\[\1\s)(?:\S+\s+)+?(?:\1\]|(?=\[\1(?:$|\s))))*\\?(?:$|\n)`, 'gm');
45
+ const blankline = new RegExp(String.raw`^(?!$|\n)(?:\\?[^\S\n]|&(?:${invisibleHTMLEntityNames.join('|')});|<wbr>|\[(#+)(?!\S|\s+\1\]|\s*\[\1(?:$|\s))((?:\s+\S+)+?)(?:\s+(\1\])|\s*(?=\[\1(?:$|\s))))*(?:\\?(?:$|\n)|(\S))`, 'gm');
46
46
 
47
47
  export function visualize<P extends Parser<HTMLElement | string>>(parser: P): P;
48
48
  export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
49
49
  return union([
50
50
  convert(
51
- source => source.replace(blankline, line => line.replace(/[\\&<\[]/g, '\x1B$&')),
51
+ source => source.replace(blankline, (line, ...$) => !$[3] ? line.replace(/[\\&<\[]/g, '\x1B$&') : line),
52
52
  verify(parser, (ns, rest, context) => !rest && hasVisible(ns, context))),
53
53
  some(union([linebreak, unescsource])),
54
54
  ]);
@@ -15,12 +15,12 @@ export function youtube(source: HTMLImageElement, url: URL): HTMLElement | undef
15
15
  function resolve(url: URL): string | undefined {
16
16
  switch (url.origin) {
17
17
  case 'https://www.youtube.com':
18
- return url.pathname === '/watch/'
19
- ? url.href.replace(/.+?=/, '').replace('&', '?')
18
+ return url.pathname.match(/^\/watch\/?$/)
19
+ ? url.searchParams.get('v')?.concat(url.search.replace(/([?&])v=[^&#]*&?/g, '$1'), url.hash)
20
20
  : undefined;
21
21
  case 'https://youtu.be':
22
- return url.pathname.match(/^\/[\w-]+$/)
23
- ? url.href.slice(url.href.indexOf('/', 9) + 1)
22
+ return url.pathname.match(/^\/[\w-]+\/?$/)
23
+ ? url.href.slice(url.origin.length)
24
24
  : undefined;
25
25
  default:
26
26
  return;