diff --git a/lib/datasource/pypi/index.ts b/lib/datasource/pypi/index.ts
index d27b3f9d6f6f50..82cb434f52abe7 100644
--- a/lib/datasource/pypi/index.ts
+++ b/lib/datasource/pypi/index.ts
@@ -1,7 +1,7 @@
import url from 'url';
import changelogFilenameRegex from 'changelog-filename-regex';
-import { parse } from 'node-html-parser';
import { logger } from '../../logger';
+import { parse } from '../../util/html';
import { Http } from '../../util/http';
import { ensureTrailingSlash } from '../../util/url';
import { matches } from '../../versioning/pep440';
@@ -195,7 +195,7 @@ async function getSimpleDependency(
logger.trace({ dependency: packageName }, 'pip package not found');
return null;
}
- const root: HTMLElement = parse(cleanSimpleHtml(dep)) as any;
+ const root: HTMLElement = parse(cleanSimpleHtml(dep));
const links = root.querySelectorAll('a');
const releases: Releases = {};
for (const link of Array.from(links)) {
diff --git a/lib/datasource/ruby-version/index.ts b/lib/datasource/ruby-version/index.ts
index fa43d545c5e17e..8f14c5054e1d26 100644
--- a/lib/datasource/ruby-version/index.ts
+++ b/lib/datasource/ruby-version/index.ts
@@ -1,7 +1,6 @@
-import { parse } from 'node-html-parser';
-
import { ExternalHostError } from '../../types/errors/external-host-error';
import * as packageCache from '../../util/cache/package';
+import { parse } from '../../util/html';
import { Http } from '../../util/http';
import { isVersion } from '../../versioning/ruby';
import { GetReleasesConfig, ReleaseResult } from '../common';
@@ -32,12 +31,12 @@ export async function getReleases(
releases: [],
};
const response = await http.get(rubyVersionsUrl);
- const root: any = parse(response.body);
+ const root: HTMLElement = parse(response.body);
const rows = root.querySelector('.release-list').querySelectorAll('tr');
- for (const row of rows) {
- const columns: string[] = Array.from(
- row.querySelectorAll('td').map((td) => td.innerHTML)
- );
+ rows.forEach((row) => {
+ const tds = row.querySelectorAll('td');
+ const columns: string[] = [];
+ tds.forEach((td) => columns.push(td.innerHTML));
if (columns.length) {
const version = columns[0].replace('Ruby ', '');
if (isVersion(version)) {
@@ -48,7 +47,7 @@ export async function getReleases(
res.releases.push({ version, releaseTimestamp, changelogUrl });
}
}
- }
+ });
await packageCache.set(cacheNamespace, 'all', res, 15);
return res;
} catch (err) {
diff --git a/lib/util/html.spec.ts b/lib/util/html.spec.ts
new file mode 100644
index 00000000000000..296fed64394e03
--- /dev/null
+++ b/lib/util/html.spec.ts
@@ -0,0 +1,16 @@
+import { getName } from '../../test/util';
+import { parse } from './html';
+
+describe(getName(__filename), () => {
+ it('parses HTML', () => {
+ const body = parse('
Hello, world!
');
+ expect(body.childElementCount).toBe(1);
+ const div = body.children[0];
+ expect(div.tagName).toBe('DIV');
+ expect(div.textContent).toBe('Hello, world!');
+ });
+ it('returns empty', () => {
+ const body = parse('');
+ expect(body.childElementCount).toBe(0);
+ });
+});
diff --git a/lib/util/html.ts b/lib/util/html.ts
new file mode 100644
index 00000000000000..f4e067eee42f4f
--- /dev/null
+++ b/lib/util/html.ts
@@ -0,0 +1,5 @@
+import { JSDOM } from 'jsdom';
+
+export function parse(html: string): HTMLElement {
+ return new JSDOM(html).window.document.body;
+}
diff --git a/package.json b/package.json
index aae0f6dbffaafb..5806b655eb61ac 100644
--- a/package.json
+++ b/package.json
@@ -139,6 +139,7 @@
"ignore": "5.1.8",
"ini": "1.3.5",
"js-yaml": "3.14.0",
+ "jsdom": "16.4.0",
"json-dup-key-validator": "1.0.2",
"json-stringify-pretty-compact": "2.0.0",
"json5": "2.1.3",
@@ -151,7 +152,6 @@
"moment": "2.27.0",
"moment-timezone": "0.5.31",
"node-emoji": "1.10.0",
- "node-html-parser": "1.2.20",
"p-all": "3.0.0",
"p-map": "4.0.0",
"parse-diff": "0.7.0",
@@ -200,6 +200,7 @@
"@types/ini": "1.3.30",
"@types/jest": "26.0.13",
"@types/js-yaml": "3.12.4",
+ "@types/jsdom": "16.2.4",
"@types/json-dup-key-validator": "1.0.0",
"@types/json5": "0.0.30",
"@types/later": "1.2.6",
@@ -252,7 +253,7 @@
"strip-ansi": "6.0.0",
"tmp-promise": "3.0.2",
"type-fest": "0.16.0",
- "typescript": "3.9.7"
+ "typescript": "4.0.2"
},
"resolutions": {
"jest-silent-reporter/jest-util": ">=25.1.0",
diff --git a/yarn.lock b/yarn.lock
index b8595c819212f5..d7bce0a2dd709d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1667,6 +1667,15 @@
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.12.4.tgz#7d3b534ec35a0585128e2d332db1403ebe057e25"
integrity sha512-fYMgzN+9e28R81weVN49inn/u798ruU91En1ZnGvSZzCRc5jXx9B2EDhlRaWmcO1RIxFHL8AajRXzxDuJu93+A==
+"@types/jsdom@16.2.4":
+ version "16.2.4"
+ resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.4.tgz#527ca99943e00561ca4056b1904fd5f4facebc3b"
+ integrity sha512-RssgLa5ptjVKRkHho/Ex0+DJWkVsYuV8oh2PSG3gKxFp8n/VNyB7kOrZGQkk2zgPlcBkIKOItUc/T5BXit9uhg==
+ dependencies:
+ "@types/node" "*"
+ "@types/parse5" "*"
+ "@types/tough-cookie" "*"
+
"@types/json-dup-key-validator@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/json-dup-key-validator/-/json-dup-key-validator-1.0.0.tgz#3a666ab980e5e957960e9341e13eabd4fd9a24f3"
@@ -1791,6 +1800,11 @@
resolved "https://registry.yarnpkg.com/@types/parse-link-header/-/parse-link-header-1.0.0.tgz#69f059e40a0fa93dc2e095d4142395ae6adc5d7a"
integrity sha512-fCA3btjE7QFeRLfcD0Sjg+6/CnmC66HpMBoRfRzd2raTaWMJV21CCZ0LO8MOqf8onl5n0EPfjq4zDhbyX8SVwA==
+"@types/parse5@*":
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
+ integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==
+
"@types/prettier@^2.0.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3"
@@ -1848,6 +1862,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
+"@types/tough-cookie@*":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d"
+ integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==
+
"@types/traverse@0.6.32":
version "0.6.32"
resolved "https://registry.yarnpkg.com/@types/traverse/-/traverse-0.6.32.tgz#f9fdfa40cd4898deaa975a14511aec731de8235e"
@@ -4863,11 +4882,6 @@ hasha@5.2.0:
is-stream "^2.0.0"
type-fest "^0.8.0"
-he@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
- integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
-
homedir-polyfill@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
@@ -6095,7 +6109,7 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
-jsdom@^16.2.2:
+jsdom@16.4.0, jsdom@^16.2.2:
version "16.4.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
@@ -7320,13 +7334,6 @@ node-gyp@^7.0.0:
tar "^6.0.1"
which "^2.0.2"
-node-html-parser@1.2.20:
- version "1.2.20"
- resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.2.20.tgz#37e9ebc627dbe3ff446eea4ac93e3d254b7c6ee4"
- integrity sha512-1fUpYjAducDrrBSE0etRUV1tM+wSFTudmrslMXuk35wL/L29E7e1CLQn4CNzFLnqtYpmDlWhkD6VUloyHA0dwA==
- dependencies:
- he "1.1.1"
-
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@@ -10256,10 +10263,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@3.9.7:
- version "3.9.7"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
- integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
+typescript@4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2"
+ integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.6"