diff --git a/.c8rc.json b/.c8rc.json index 71957531..e57eafd9 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -1,6 +1,6 @@ { - "statements": "78", - "branches": "78", - "functions": "82", - "lines": "78" + "statements": "80", + "branches": "84", + "functions": "88", + "lines": "80" } diff --git a/lib/allowlist.ts b/lib/allowlist.ts index 933f0c58..615b2cd4 100644 --- a/lib/allowlist.ts +++ b/lib/allowlist.ts @@ -1,5 +1,5 @@ import type { GitHubAdvisoryId } from "audit-types"; -import { isGitHubAdvisoryId } from "./common"; +import { deduplicate, isGitHubAdvisoryId } from "./common"; import type { AuditCiPreprocessedConfig } from "./config"; class Allowlist { @@ -37,12 +37,8 @@ class Allowlist { config: Pick ) { const { allowlist } = config; - // It's possible someone duplicated the inputs. - // The solution is to merge into one array, change to set, and back to array. - // This will remove duplicates. - const set = new Set(allowlist || []); - const input = [...set]; - const allowlistObject = new Allowlist(input); + const deduplicatedAllowlist = deduplicate(allowlist || []); + const allowlistObject = new Allowlist(deduplicatedAllowlist); return allowlistObject; } } diff --git a/lib/audit.ts b/lib/audit.ts index 8b834c18..e948007c 100644 --- a/lib/audit.ts +++ b/lib/audit.ts @@ -15,7 +15,9 @@ const PARTIAL_RETRY_ERROR_MSG = { yarn: "503 Service Unavailable", }; -function getAuditor(packageManager: "npm" | "yarn" | "pnpm") { +function getAuditor( + packageManager: "npm" | "yarn" | "pnpm" +): typeof yarnAuditer | typeof npmAuditer | typeof pnpmAuditer { switch (packageManager) { case "yarn": return yarnAuditer; diff --git a/lib/common.ts b/lib/common.ts index c7f087ca..9353141a 100644 --- a/lib/common.ts +++ b/lib/common.ts @@ -186,8 +186,8 @@ export function matchString(template: string, string_: string) { : template === string_; } -export function isGitHubAdvisoryId(id: string): id is GitHubAdvisoryId { - return id.startsWith("GHSA"); +export function isGitHubAdvisoryId(id: unknown): id is GitHubAdvisoryId { + return typeof id === "string" && id.startsWith("GHSA"); } export function gitHubAdvisoryUrlToAdvisoryId(url: string): GitHubAdvisoryId { @@ -199,3 +199,7 @@ export function gitHubAdvisoryIdToUrl( ): `https://github.com/advisories/${T}` { return `https://github.com/advisories/${id}`; } + +export function deduplicate(array: readonly string[]) { + return [...new Set(array)]; +} diff --git a/package-lock.json b/package-lock.json index 5b560f2e..a8ffa815 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@types/node": "^12.20.47", "@types/readline-transform": "^1.0.1", "@types/semver": "^7.3.9", + "@types/sinon": "^10.0.11", "@types/yargs": "^17.0.9", "@typescript-eslint/eslint-plugin": "^5.14.0", "@typescript-eslint/parser": "^5.14.0", @@ -45,6 +46,7 @@ "mocha": "^9.2.2", "prettier": "^2.5.1", "pretty-quick": "^3.1.3", + "sinon": "^14.0.0", "ts-json-schema-generator": "^0.98.0", "typescript": "^4.6.2" }, @@ -252,6 +254,41 @@ "node": ">= 8" } }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz", + "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "node_modules/@types/chai": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", @@ -348,6 +385,21 @@ "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", "dev": true }, + "node_modules/@types/sinon": { + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.11.tgz", + "integrity": "sha512-dmZsHlBsKUtBpHriNjlK0ndlvEh8dcb9uV9Afsbt89QIyydpC7NcR+nWlAhASfy3GHnxTl4FX/aKE7XZUt/B4g==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "node_modules/@types/yargs": { "version": "17.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz", @@ -2417,6 +2469,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2555,6 +2613,12 @@ "node": "*" } }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2593,6 +2657,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2959,6 +3029,19 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node_modules/nise": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz", + "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": ">=5", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "node_modules/normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3190,6 +3273,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3776,6 +3868,45 @@ "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, + "node_modules/sinon": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.0.tgz", + "integrity": "sha512-ugA6BFmE+WrJdh0owRZHToLd32Uw3Lxq6E6LtNRU+xTVBefx632h03Q7apXWRsRdZAJ41LB8aUfn2+O4jsDNMw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^9.1.2", + "@sinonjs/samsam": "^6.1.1", + "diff": "^5.0.0", + "nise": "^5.1.1", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -4468,6 +4599,41 @@ "fastq": "^1.6.0" } }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/samsam": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz", + "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, "@types/chai": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", @@ -4564,6 +4730,21 @@ "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", "dev": true }, + "@types/sinon": { + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.11.tgz", + "integrity": "sha512-dmZsHlBsKUtBpHriNjlK0ndlvEh8dcb9uV9Afsbt89QIyydpC7NcR+nWlAhASfy3GHnxTl4FX/aKE7XZUt/B4g==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "@types/yargs": { "version": "17.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.9.tgz", @@ -6052,6 +6233,12 @@ "call-bind": "^1.0.0" } }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -6162,6 +6349,12 @@ "through": ">=2.2.7 <3" } }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -6194,6 +6387,12 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6463,6 +6662,19 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "nise": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz", + "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": ">=5", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -6633,6 +6845,15 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -7026,6 +7247,37 @@ "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, + "sinon": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.0.tgz", + "integrity": "sha512-ugA6BFmE+WrJdh0owRZHToLd32Uw3Lxq6E6LtNRU+xTVBefx632h03Q7apXWRsRdZAJ41LB8aUfn2+O4jsDNMw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^9.1.2", + "@sinonjs/samsam": "^6.1.1", + "diff": "^5.0.0", + "nise": "^5.1.1", + "supports-color": "^7.2.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", diff --git a/package.json b/package.json index 15c32730..5229da69 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "audit-ci": "./dist/bin.js" }, "files": [ - "dist/*", + "dist/*.js", + "dist/*.d.ts", "README.md" ], "scripts": { @@ -60,6 +61,7 @@ "@types/node": "^12.20.47", "@types/readline-transform": "^1.0.1", "@types/semver": "^7.3.9", + "@types/sinon": "^10.0.11", "@types/yargs": "^17.0.9", "@typescript-eslint/eslint-plugin": "^5.14.0", "@typescript-eslint/parser": "^5.14.0", @@ -74,6 +76,7 @@ "mocha": "^9.2.2", "prettier": "^2.5.1", "pretty-quick": "^3.1.3", + "sinon": "^14.0.0", "ts-json-schema-generator": "^0.98.0", "typescript": "^4.6.2" }, diff --git a/test/audit-ci-version.spec.js b/test/audit-ci-version.spec.js index 3b42b599..6487b305 100644 --- a/test/audit-ci-version.spec.js +++ b/test/audit-ci-version.spec.js @@ -1,6 +1,11 @@ // @ts-check +const { expect } = require("chai"); const semver = require("semver"); -const { auditCiVersion } = require("../dist/audit-ci-version"); +const sinon = require("sinon"); +const { + auditCiVersion, + printAuditCiVersion, +} = require("../dist/audit-ci-version"); describe("audit-ci package", () => { it("gets the version of the audit-ci package", () => { @@ -8,4 +13,18 @@ describe("audit-ci package", () => { semver.valid(packageVersion); semver.gte(packageVersion, "2.4.2"); }); + it("prints audit-ci version", () => { + const stub = sinon.stub(console, "log"); + printAuditCiVersion("text"); + expect(stub.calledOnceWithExactly(`audit-ci version: ${auditCiVersion}`)); + // @ts-expect-error restoring console.log + console.log.restore(); + }); + it("does not print audit-ci version with JSON reporting", () => { + const stub = sinon.stub(console, "log"); + printAuditCiVersion("json"); + expect(stub.notCalled); + // @ts-expect-error restoring console.log + console.log.restore(); + }); }); diff --git a/test/common.spec.js b/test/common.spec.js index e68c4ffb..7f8de705 100644 --- a/test/common.spec.js +++ b/test/common.spec.js @@ -3,7 +3,10 @@ const { expect } = require("chai"); const { matchString, gitHubAdvisoryUrlToAdvisoryId, + gitHubAdvisoryIdToUrl, + isGitHubAdvisoryId, } = require("../dist/common"); +const { deduplicate } = require("../dist/common"); describe("matchString", () => { it("works for various prefixes and suffixes of wildcards", () => { @@ -26,3 +29,49 @@ describe("gitHubAdvisoryUrlToAdvisoryId", () => { ).to.eql("GHSA-1"); }); }); + +describe("gitHubAdvisoryIdToUrl", () => { + it("converts a GitHub advisory identifier to the GitHub URL for the advisory", () => { + const id = "GHSA-qrpm-p2h7-hrv2"; + expect(gitHubAdvisoryIdToUrl(id)).to.eql( + `https://github.com/advisories/${id}` + ); + }); + it("does not handle null or undefined in a special way", () => { + // @ts-expect-error testing null + // eslint-disable-next-line unicorn/no-null + expect(gitHubAdvisoryIdToUrl(null)).to.eql( + `https://github.com/advisories/null` + ); + // @ts-expect-error testing undefined + // eslint-disable-next-line unicorn/no-useless-undefined + expect(gitHubAdvisoryIdToUrl(undefined)).to.eql( + `https://github.com/advisories/undefined` + ); + }); +}); + +describe("deduplicate", () => { + it("removes duplicates from an array", () => { + expect(deduplicate(["1", "2", "2", "1", "2", "3", "1"])).to.deep.equal([ + "1", + "2", + "3", + ]); + }); +}); + +describe("isGitHubAdvisoryId", () => { + it("returns true for valid GitHub advisory IDs", () => { + expect(isGitHubAdvisoryId("GHSA-qrpm-p2h7-hrv2")).to.be.true; + expect(isGitHubAdvisoryId("GHSA-random")).to.be.true; // lazy implementation + expect(isGitHubAdvisoryId("GHSA")).to.be.true; // lazy implementation + }); + it("returns false for invalid GitHub advisory IDs", () => { + expect(isGitHubAdvisoryId("qrpm-p2h7-hrv2")).to.be.false; + // eslint-disable-next-line unicorn/no-useless-undefined + expect(isGitHubAdvisoryId(undefined)).to.be.false; + // eslint-disable-next-line unicorn/no-null + expect(isGitHubAdvisoryId(null)).to.be.false; + }); +}); diff --git a/tsconfig.build.json b/tsconfig.build.json index 65b3af63..cbbae4bc 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -2,7 +2,12 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./dist", - "noEmit": false + "noEmit": false, + "sourceMap": true, + "declaration": true, + "declarationMap": true, + // Only needed for tests, disabled in build + "resolveJsonModule": false }, "include": ["lib"] } diff --git a/tsconfig.json b/tsconfig.json index a0b15b68..e01b4514 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,9 @@ "noEmit": true, // TODO: Remove noImplicitAny: false "noImplicitAny": false, - "esModuleInterop": true + "esModuleInterop": true, + // Only needed for tests, disabled in build + "resolveJsonModule": true }, "include": ["lib", "test"] }