diff --git a/.eslintrc b/.eslintrc index d190504..7da237f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,10 +3,11 @@ "ecmaVersion": 2017 }, "env": { + "jest": true, "node": true }, - "extends": "eslint:recommended", - "plugins": ["prettier"], + "extends": ["eslint:recommended", "plugin:jest/recommended", "prettier"], + "plugins": ["jest", "prettier"], "rules": { "prettier/prettier": "error" } diff --git a/jest-runner-eslint.config.js b/jest-runner-eslint.config.js new file mode 100644 index 0000000..a9fedf8 --- /dev/null +++ b/jest-runner-eslint.config.js @@ -0,0 +1,5 @@ +module.exports = { + cliOptions: { + format: "pretty" + } +}; diff --git a/jest.eslint.config.js b/jest.eslint.config.js new file mode 100644 index 0000000..1294747 --- /dev/null +++ b/jest.eslint.config.js @@ -0,0 +1,6 @@ +module.exports = { + runner: "jest-runner-eslint", + displayName: "eslint", + modulePathIgnorePatterns: ["dist"], + testMatch: ["/**/*.js"] +}; diff --git a/jest.test.config.js b/jest.test.config.js new file mode 100644 index 0000000..a54d47b --- /dev/null +++ b/jest.test.config.js @@ -0,0 +1,5 @@ +module.exports = { + displayName: "test", + testEnvironment: "node", + moduleDirectories: ["src", "node_modules"] +}; diff --git a/package-lock.json b/package-lock.json index 405ac80..171c174 100644 --- a/package-lock.json +++ b/package-lock.json @@ -500,29 +500,11 @@ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", "dev": true }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -1001,6 +983,32 @@ "unset-value": "^1.0.0" } }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, "callsites": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", @@ -1336,6 +1344,36 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cosmiconfig": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz", + "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0" + }, + "dependencies": { + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", @@ -1373,6 +1411,27 @@ "sha.js": "^2.4.8" } }, + "create-jest-runner": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/create-jest-runner/-/create-jest-runner-0.4.1.tgz", + "integrity": "sha512-JOy675JMZ3b05F3VfAAi6Igme3pVBWu7Rt+gbW9ujAiX/Dua7+G47O7IbfiUU/FZjXhtipu/tz930b++UMGQEA==", + "dev": true, + "requires": { + "jest-worker": "^23.2.0", + "throat": "^4.1.0" + }, + "dependencies": { + "jest-worker": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", + "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", + "dev": true, + "requires": { + "merge-stream": "^1.0.1" + } + } + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1792,6 +1851,36 @@ "text-table": "^0.2.0" } }, + "eslint-config-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.0.0.tgz", + "integrity": "sha512-kWuiJxzV5NwOwZcpyozTzDT5KJhBw292bbYro9Is7BWnbNMg15Gmpluc1CTetiCatF8DRkNvgPAOaSyg+bYr3g==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + } + }, + "eslint-formatter-pretty": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-2.1.1.tgz", + "integrity": "sha512-gWfagucSWBn82WxzwFloBTLAcwYDgnpAfiV5pQfyAV5YpZikuLflRU8nc3Ts9wnNvLhwk4blzb42/C495Yw7BA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.1.0", + "chalk": "^2.1.0", + "eslint-rule-docs": "^1.1.5", + "log-symbols": "^2.0.0", + "plur": "^3.0.1", + "string-width": "^2.0.0", + "supports-hyperlinks": "^1.0.1" + } + }, + "eslint-plugin-jest": { + "version": "22.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.2.2.tgz", + "integrity": "sha512-hnWgh9o39VJfz6lJEyQJdTW7dN2yynlGkmPOlU/oMHh+d7WVMsJP1GeDTB520VCDljEdKExCwD5IBpQIUl4mJg==", + "dev": true + }, "eslint-plugin-prettier": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.0.1.tgz", @@ -1801,6 +1890,12 @@ "prettier-linter-helpers": "^1.0.0" } }, + "eslint-rule-docs": { + "version": "1.1.56", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.56.tgz", + "integrity": "sha512-9+YFz4ZvBj43mUNJg+jUVA/xOO4eywkn2yEOjZwgNBpyhcV1mFnz5hILDxfSTJdA5Y5YY8QbonoFmRneX51bcg==", + "dev": true + }, "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", @@ -2828,6 +2923,12 @@ "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -3182,6 +3283,12 @@ "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, + "irregular-plurals": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-2.0.0.tgz", + "integrity": "sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw==", + "dev": true + }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -3292,6 +3399,12 @@ } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -3812,6 +3925,18 @@ "throat": "^4.0.0" } }, + "jest-runner-eslint": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/jest-runner-eslint/-/jest-runner-eslint-0.7.3.tgz", + "integrity": "sha512-MywU/1Fm+0PisAyYSeJ0MsmSD3oGfWyCbkgvBWu7xEChCIiCMaQ+3Cm3AvAIJZPvVlDtQtKN6lEa2QcMyF3DGQ==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cosmiconfig": "^5.0.0", + "create-jest-runner": "^0.4.1", + "eslint": "^5.6.0" + } + }, "jest-runtime": { "version": "24.0.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.0.0.tgz", @@ -4055,12 +4180,6 @@ } } }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4212,6 +4331,15 @@ "lodash._reinterpolate": "~3.0.0" } }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4304,12 +4432,6 @@ "readable-stream": "^2.0.1" } }, - "memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, "merge": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", @@ -4605,23 +4727,6 @@ "remove-trailing-separator": "^1.0.1" } }, - "npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -4982,12 +5087,6 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, - "pidtree": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", - "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", - "dev": true - }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -5012,6 +5111,15 @@ "find-up": "^3.0.0" } }, + "plur": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/plur/-/plur-3.0.1.tgz", + "integrity": "sha512-lJl0ojUynAM1BZn58Pas2WT/TXeC1+bS+UqShl0x9+49AtOn7DixRXVzaC8qrDOIxNDmepKnLuMTH7NQmkX0PA==", + "dev": true, + "requires": { + "irregular-plurals": "^2.0.0" + } + }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -5612,18 +5720,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -6050,17 +6146,6 @@ "strip-ansi": "^4.0.0" } }, - "string.prototype.padend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", - "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.4.3", - "function-bind": "^1.0.2" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6105,6 +6190,24 @@ "has-flag": "^3.0.0" } }, + "supports-hyperlinks": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", + "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", + "dev": true, + "requires": { + "has-flag": "^2.0.0", + "supports-color": "^5.0.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + } + } + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", diff --git a/package.json b/package.json index d1f5633..722d222 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,7 @@ ], "main": "src/index.js", "scripts": { - "test:eslint": "eslint .", - "test:jest": "jest", - "test": "run-s test:*" + "test": "jest --projects jest.*.config.js" }, "peerDependencies": { "webpack": "^4.0.0" @@ -37,10 +35,13 @@ }, "devDependencies": { "eslint": "^5.12.1", + "eslint-config-prettier": "^4.0.0", + "eslint-formatter-pretty": "^2.1.1", "eslint-plugin-prettier": "^3.0.1", - "npm-run-all": "^4.1.5", - "prettier": "^1.16.3", + "eslint-plugin-jest": "^22.2.2", "jest": "^24.0.0", + "jest-runner-eslint": "^0.7.3", + "prettier": "^1.16.3", "webpack": "^4.29.0" } } diff --git a/src/licenseUtils.js b/src/licenseUtils.js index 4376c68..406ef7c 100644 --- a/src/licenseUtils.js +++ b/src/licenseUtils.js @@ -18,23 +18,34 @@ const getLicenseContents = dependencyPath => { return licensePath && wrap(readFileSync(licensePath).toString(), licenseWrap); }; -const getLicenseName = package => { - if (package.licenses) { - const licenseName = package.licenses.map(license => license.type).join(" OR "); - return package.licenses.length > 1 ? `(${licenseName})` : licenseName; - } - - return package.license; -} +const getLicenseName = pkg => { + // Valid license formats are an SPDX string expression + // https://www.npmjs.com/package/spdx + if (typeof pkg.license === "string") { + return pkg.license; + } + // Check for deprecated licence formats + // https://docs.npmjs.com/files/package.json#license + if (typeof pkg.license === "object") { + return pkg.license.type || ""; + } + if (pkg.licenses && Array.isArray(pkg.licenses)) { + const licenseName = pkg.licenses.map(license => license.type).join(" OR "); + // Return the list of licenses as a composite license expression + return pkg.licenses.length > 1 ? `(${licenseName})` : licenseName; + } + // Fall-back to an empty string and let the validation handle the error. + return ""; +}; const getLicenseInformationForDependency = dependencyPath => { - const package = require(`${dependencyPath}/package.json`); + const pkg = require(`${dependencyPath}/package.json`); return { - name: package.name, - version: package.version, - author: (package.author && package.author.name) || package.author, - repository: (package.repository && package.repository.url) || package.repository, - licenseName: getLicenseName(package), + name: pkg.name, + version: pkg.version, + author: (pkg.author && pkg.author.name) || pkg.author, + repository: (pkg.repository && pkg.repository.url) || pkg.repository, + licenseName: getLicenseName(pkg), licenseText: getLicenseContents(dependencyPath) }; }; @@ -115,6 +126,7 @@ const writeLicenseInformation = (outputWriter, dependencies) => { }; module.exports = { + getLicenseName, getLicenseInformationForCompilation, getLicenseViolations, getSortedLicenseInformation, diff --git a/src/licenseUtils.spec.js b/src/licenseUtils.spec.js new file mode 100644 index 0000000..d0a70a5 --- /dev/null +++ b/src/licenseUtils.spec.js @@ -0,0 +1,53 @@ +const { getLicenseName } = require("./licenseUtils"); + +describe("getLicenseName", () => { + let pkg; + let licenseName; + describe("with valid license format", () => { + beforeEach(() => { + pkg = { license: "MIT" }; + licenseName = getLicenseName(pkg); + }); + it(`should return "MIT" license name`, () => { + expect(licenseName).toBe("MIT"); + }); + }); + describe("with deprecated license format (as object)", () => { + beforeEach(() => { + pkg = { license: { type: "MIT" } }; + licenseName = getLicenseName(pkg); + }); + it(`should return "MIT" license name`, () => { + expect(licenseName).toBe("MIT"); + }); + }); + describe("with deprecated license format (as array)", () => { + describe("with only one license", () => { + beforeEach(() => { + pkg = { licenses: [{ type: "MIT" }] }; + licenseName = getLicenseName(pkg); + }); + it(`should return "MIT" license name`, () => { + expect(licenseName).toBe("MIT"); + }); + }); + describe("with multiple licenses", () => { + beforeEach(() => { + pkg = { licenses: [{ type: "MIT" }, { type: "BSD-3-Clause" }] }; + licenseName = getLicenseName(pkg); + }); + it("should return composite license names as OR", () => { + expect(licenseName).toBe("(MIT OR BSD-3-Clause)"); + }); + }); + }); + describe("with unknown license value of format", () => { + beforeEach(() => { + pkg = { foo: "bar" }; + licenseName = getLicenseName(pkg); + }); + it("should return empty string", () => { + expect(licenseName).toBe(""); + }); + }); +});