diff --git a/lib/license.js b/lib/license.js new file mode 100644 index 0000000..6428e83 --- /dev/null +++ b/lib/license.js @@ -0,0 +1,27 @@ +// This is an implementation of the validForNewPackage flag in validate-npm-package-license, which is no longer maintained + +const parse = require('spdx-expression-parse') + +function usesLicenseRef (ast) { + if (Object.hasOwn(ast, 'license')) { + return ast.license.startsWith('LicenseRef') || ast.license.startsWith('DocumentRef') + } else { + return usesLicenseRef(ast.left) || usesLicenseRef(ast.right) + } +} + +// license should be a valid SPDX license expression (without "LicenseRef"), "UNLICENSED", or "SEE LICENSE IN " +module.exports = function licenseValidForNewPackage (argument) { + if (argument === 'UNLICENSED' || argument === 'UNLICENCED') { + return true + } + if (/^SEE LICEN[CS]E IN ./.test(argument)) { + return true + } + try { + const ast = parse(argument) + return !usesLicenseRef(ast) + } catch { + return false + } +} diff --git a/lib/normalize-data.js b/lib/normalize-data.js index 1c1a369..7bd86b5 100644 --- a/lib/normalize-data.js +++ b/lib/normalize-data.js @@ -2,7 +2,7 @@ const { URL } = require('node:url') const hostedGitInfo = require('hosted-git-info') -const validateLicense = require('validate-npm-package-license') +const validateLicense = require('./license.js') const typos = { dependancies: 'dependencies', @@ -230,7 +230,7 @@ function normalizeData (data, changes) { changes?.push('No license field.') } else if (typeof (license) !== 'string' || license.length < 1 || license.trim() === '') { changes?.push('license should be a valid SPDX license expression') - } else if (!validateLicense(license).validForNewPackages) { + } else if (!validateLicense(license)) { changes?.push('license should be a valid SPDX license expression') } // fixPeople diff --git a/package.json b/package.json index a249571..ed3d383 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" + "spdx-expression-parse": "^4.0.0" }, "devDependencies": { "@npmcli/eslint-config": "^6.0.0", diff --git a/tap-snapshots/test/normalize-data.js.test.cjs b/tap-snapshots/test/normalize-data.js.test.cjs index 541348e..c2dbe12 100644 --- a/tap-snapshots/test/normalize-data.js.test.cjs +++ b/tap-snapshots/test/normalize-data.js.test.cjs @@ -166,6 +166,18 @@ exports[`test/normalize-data.js TAP fixKeywordsField splits string > must match Array [] ` +exports[`test/normalize-data.js TAP fixLicenseField SPDX > must match snapshot 1`] = ` +Array [] +` + +exports[`test/normalize-data.js TAP fixLicenseField SPDX LEFT and RIGHT > must match snapshot 1`] = ` +Array [] +` + +exports[`test/normalize-data.js TAP fixLicenseField file ref > must match snapshot 1`] = ` +Array [] +` + exports[`test/normalize-data.js TAP fixLicenseField invalid > must match snapshot 1`] = ` Array [ "license should be a valid SPDX license expression", diff --git a/test/normalize-data.js b/test/normalize-data.js index 8863211..0e0293f 100644 --- a/test/normalize-data.js +++ b/test/normalize-data.js @@ -330,6 +330,30 @@ t.test('fixLicenseField', async t => { }) t.equal(content.license, 'BESPOKE LICENSE') }) + + t.test('SPDX', async t => { + const { content } = await normalizeData(t, { + ...base, + license: 'MIT', + }) + t.equal(content.license, 'MIT') + }) + + t.test('file ref', async t => { + const { content } = await normalizeData(t, { + ...base, + license: 'SEE LICENSE IN LICENSE.TXT', + }) + t.equal(content.license, 'SEE LICENSE IN LICENSE.TXT') + }) + + t.test('SPDX LEFT and RIGHT', async t => { + const { content } = await normalizeData(t, { + ...base, + license: 'MIT or ISC', + }) + t.equal(content.license, 'MIT or ISC') + }) }) t.test('fixPeople', async t => {