license-checker
Advanced tools
Comparing version 12.1.0 to 13.0.0
## Change Log | ||
### v12.1.0 (2017/07/12 16:47 +00:00) | ||
### v13.0.0 (2017/07/14 12:49 +00:00) | ||
- [051b20b](https://github.com/davglass/license-checker/commit/051b20b0c4b35f223f724705a0025dafc809373f) cleaned up some tests (@davglass) | ||
- [#110](https://github.com/davglass/license-checker/pull/110) FEATURE: Recognise some custom licenses by file or url (#110) (@dancrumb) | ||
- [#111](https://github.com/davglass/license-checker/pull/111) Resolves #60 (#111) Adding support for GPL and LGPL (@dancrumb) | ||
- [#109](https://github.com/davglass/license-checker/pull/109) FEATURE: Improve license exclusion (#109) (@dancrumb) | ||
- [#108](https://github.com/davglass/license-checker/pull/108) FEATURE: Detect private modules and report them as UNLICENSED (#108) (@dancrumb) | ||
### v12.1.0 (2017/07/12 16:48 +00:00) | ||
- [dc944e5](https://github.com/davglass/license-checker/commit/dc944e54d55d77b0ef6b6321d9abee847662ccb8) 12.1.0 (@davglass) | ||
- [d415c58](https://github.com/davglass/license-checker/commit/d415c580b04bc5eefa592dc9f9a0a31b244c1bd3) updated contrib and changes (@davglass) | ||
- [#107](https://github.com/davglass/license-checker/pull/107) Merge pull request #107 from dancrumb/feature/support-for-public-domain-licenses (@dancrumb) | ||
@@ -5,0 +14,0 @@ - [0c55770](https://github.com/davglass/license-checker/commit/0c55770294167161c48b79cc82a15a6545154a87) FEATURE: Add support for Public Domain licenses (@dancrumb) |
@@ -8,2 +8,3 @@ /* | ||
var UNKNOWN = 'UNKNOWN'; | ||
var UNLICENSED = 'UNLICENSED'; | ||
var fs = require('fs'); | ||
@@ -17,2 +18,4 @@ var path = require('path'); | ||
var mkdirp = require('mkdirp'); | ||
var spdxSatisfies = require('spdx-satisfies'); | ||
var spdxCorrect =require('spdx-correct'); | ||
@@ -41,2 +44,5 @@ // Set up debug logging | ||
if (json.private) { | ||
moduleInfo.private = true; | ||
} | ||
@@ -110,5 +116,6 @@ // If we have processed this key already, just return the data object. | ||
licenseData = json.license || json.licenses || undefined; | ||
if (json.path && (!json.readme || json.readme.toLowerCase().indexOf('no readme data found') > -1)) { | ||
readmeFile = path.join(json.path, 'README.md'); | ||
/*istanbul ignore if*/ | ||
if (fs.existsSync(readmeFile)) { | ||
@@ -179,2 +186,3 @@ json.readme = fs.readFileSync(readmeFile, 'utf8').toString(); | ||
/*istanbul ignore else*/ | ||
if (include("licenseFile")) { | ||
@@ -185,2 +193,3 @@ moduleInfo.licenseFile = options.basePath ? path.relative(options.basePath, licenseFile) : licenseFile; | ||
if (include("licenseText") && options.customFormat) { | ||
/*istanbul ignore else*/ | ||
if (options._args && !options._args.csv) { | ||
@@ -265,20 +274,21 @@ moduleInfo.licenseText = content.trim(); | ||
var colorizeString = function(string) { | ||
/*istanbul ignore next*/ | ||
return colorize ? chalk.bold.red(string) : string; | ||
}; | ||
Object.keys(data).sort().forEach(function(item) { | ||
if(data[item].private) { | ||
data[item].licenses = colorizeString(UNLICENSED); | ||
} | ||
/*istanbul ignore next*/ | ||
if (!data[item].licenses) { | ||
/*istanbul ignore next*/ | ||
if (colorize) { | ||
data[item].licenses = chalk.bold.red(UNKNOWN); | ||
} else { | ||
data[item].licenses = UNKNOWN; | ||
} | ||
data[item].licenses = colorizeString(UNKNOWN); | ||
} | ||
if (options.unknown) { | ||
/*istanbul ignore else*/ | ||
if (data[item].licenses && data[item].licenses !== UNKNOWN) { | ||
if (data[item].licenses.indexOf('*') > -1) { | ||
/*istanbul ignore if*/ | ||
if (colorize) { | ||
data[item].licenses = chalk.bold.red(UNKNOWN); | ||
} else { | ||
data[item].licenses = UNKNOWN; | ||
} | ||
data[item].licenses = colorizeString(UNKNOWN); | ||
} | ||
@@ -291,3 +301,3 @@ } | ||
if (data[item].licenses.indexOf('*') > -1 || | ||
data[item].licenses.indexOf('UNKNOWN') > -1) { | ||
data[item].licenses.indexOf(UNKNOWN) > -1) { | ||
sorted[item] = data[item]; | ||
@@ -301,5 +311,44 @@ } | ||
if (exclude) { | ||
var transformBSD = function(spdx) { | ||
return spdx === 'BSD' ? '(0BSD OR BSD-2-Clause OR BSD-3-Clause OR BSD-4-Clause)' : spdx; | ||
}; | ||
var invert = function(fn) { return function(spdx) { return !fn(spdx);};}; | ||
var spdxIsValid = function(spdx) { return spdxCorrect(spdx) === spdx; }; | ||
var validSPDXLicenses = exclude.map(transformBSD).filter(spdxIsValid); | ||
var invalidSPDXLicenses = exclude.map(transformBSD).filter(invert(spdxIsValid)); | ||
var spdxExcluder = '( ' + validSPDXLicenses.join(' OR ') + ' )'; | ||
Object.keys(sorted).forEach(function(item) { | ||
if (!(sorted[item].licenses && exclude.indexOf(sorted[item].licenses) !== -1)) { | ||
var licenses = sorted[item].licenses; | ||
/*istanbul ignore if - just for protection*/ | ||
if(!licenses) { | ||
filtered[item] = sorted[item]; | ||
} else { | ||
licenses = [].concat(licenses); | ||
var licenseMatch = false; | ||
licenses.forEach(function(license) { | ||
/*istanbul ignore if - just for protection*/ | ||
if (license.indexOf(UNKNOWN) >= 0) { // necessary due to colorization | ||
filtered[item] = sorted[item]; | ||
} else { | ||
if(license.indexOf('*') >= 0) { | ||
license = license.substring(0, license.length - 1); | ||
} | ||
if(license === 'BSD') { | ||
license = '(0BSD OR BSD-2-Clause OR BSD-3-Clause OR BSD-4-Clause)'; | ||
} | ||
if (invalidSPDXLicenses.indexOf(license) >= 0) { | ||
licenseMatch = true; | ||
} else if(spdxCorrect(license) === null) { | ||
licenseMatch = true; | ||
} else if (spdxSatisfies(spdxCorrect(license), spdxExcluder)) { | ||
licenseMatch = true; | ||
} | ||
} | ||
}); | ||
if(!licenseMatch) { | ||
filtered[item] = sorted[item]; | ||
} | ||
} | ||
@@ -349,2 +398,3 @@ }); | ||
textArr = []; | ||
/*istanbul ignore next*/ | ||
if (csvComponentPrefix) { textArr.push(prefixName); } | ||
@@ -373,2 +423,3 @@ ['"module name"','"license"','"repository"'].forEach(function(item) { | ||
} else { | ||
/*istanbul ignore next*/ | ||
if (csvComponentPrefix) { | ||
@@ -375,0 +426,0 @@ lineArr.push('"'+prefix+'"'); |
@@ -11,2 +11,4 @@ var spdx = require('spdx'); | ||
var ISC = /ISC\b/; | ||
var GPL = /GNU GENERAL PUBLIC LICENSE\s*Version ([^,]*)/i; | ||
var LGPL = /(?:LESSER|LIBRARY) GENERAL PUBLIC LICENSE\s*Version ([^,]*)/i; | ||
var APACHE = /Apache License\b/; | ||
@@ -17,5 +19,8 @@ var WTFPL = /WTFPL\b/; | ||
var PUBLIC_DOMAIN = /[Pp]ublic [Dd]omain/; | ||
var IS_URL = /(https?:\/\/[-a-zA-Z0-9\/.]*)/; | ||
var IS_FILE_REFERENCE = /SEE LICENSE IN (.*)/i; | ||
module.exports = function(str) { | ||
var match, version; | ||
if (spdx.valid(str || '')) { | ||
@@ -52,6 +57,26 @@ return str; | ||
return 'CC0-1.0*'; | ||
} else if(GPL.test(str)) { | ||
match = GPL.exec(str); | ||
version = match[1]; | ||
if(version.length === 1) { | ||
version = version + '.0'; | ||
} | ||
return 'GPL-'+version+'*'; | ||
} else if(LGPL.test(str)) { | ||
match = LGPL.exec(str); | ||
version = match[1]; | ||
if(version.length === 1) { | ||
version = version + '.0'; | ||
} | ||
return 'LGPL-'+version+'*'; | ||
} else if(PUBLIC_DOMAIN.test(str)) { | ||
return 'Public Domain'; | ||
} else { | ||
match = IS_URL.exec(str) || IS_FILE_REFERENCE.exec(str); | ||
if(match) { | ||
return 'Custom: ' + match[1]; | ||
} else { | ||
return null; | ||
} | ||
} | ||
return null; | ||
}; |
@@ -5,3 +5,3 @@ { | ||
"author": "Dav Glass <davglass@gmail.com>", | ||
"version": "12.1.0", | ||
"version": "13.0.0", | ||
"contributors": [ | ||
@@ -50,2 +50,4 @@ "Adam Weber <adamweber01@gmail.com>", | ||
"spdx": "^0.5.1", | ||
"spdx-correct": "^2.0.3", | ||
"spdx-satisfies": "^0.1.3", | ||
"treeify": "^1.0.1" | ||
@@ -52,0 +54,0 @@ }, |
@@ -80,2 +80,11 @@ NPM License Checker | ||
Exclusions | ||
---------- | ||
A list of licenses is the simples way to describe what you want to exclude. | ||
You can use valid [SPDX identifiers](https://spdx.org/licenses/). | ||
You can use valid SPDX expressions like `MIT OR X11`. | ||
You can use non-valid SPDX identifiers, like `Public Domain`, since `npm` does | ||
support some license strings that are not SPDX identifiers. | ||
Examples | ||
@@ -89,3 +98,3 @@ -------- | ||
license-checker --customPath customFormatExample.json | ||
license-checker --exclude 'MIT, MIT/X11, BSD, ISC' | ||
license-checker --exclude 'MIT, MIT OR X11, BSD, ISC' | ||
license-checker --onlyunknown | ||
@@ -92,0 +101,0 @@ ``` |
@@ -24,2 +24,22 @@ var assert = require('assert'), | ||
it('GPL word check', function() { | ||
var data; | ||
data = license('GNU GENERAL PUBLIC LICENSE \nVersion 1, February 1989'); | ||
assert.equal(data, 'GPL-1.0*'); | ||
data = license('GNU GENERAL PUBLIC LICENSE \nVersion 2, June 1991'); | ||
assert.equal(data, 'GPL-2.0*'); | ||
data = license('GNU GENERAL PUBLIC LICENSE \nVersion 3, 29 June 2007'); | ||
assert.equal(data, 'GPL-3.0*'); | ||
}); | ||
it('LGPL word check', function() { | ||
var data; | ||
data = license('GNU LIBRARY GENERAL PUBLIC LICENSE\nVersion 2, June 1991'); | ||
assert.equal(data, 'LGPL-2.0*'); | ||
data = license('GNU LESSER GENERAL PUBLIC LICENSE\nVersion 2.1, February 1999'); | ||
assert.equal(data, 'LGPL-2.1*'); | ||
data = license('GNU LESSER GENERAL PUBLIC LICENSE \nVersion 3, 29 June 2007'); | ||
assert.equal(data, 'LGPL-3.0*'); | ||
}); | ||
it('BSD check', function() { | ||
@@ -79,3 +99,19 @@ var data = license('asdf\nRedistribution and use in source and binary forms, with or without\nasdf\n'); | ||
it('License at URL check', function() { | ||
var data = license('http://example.com/foo'); | ||
assert.equal(data, 'Custom: http://example.com/foo'); | ||
data = license('See license at http://example.com/foo'); | ||
assert.equal(data, 'Custom: http://example.com/foo'); | ||
data = license('https://example.com/foo'); | ||
assert.equal(data, 'Custom: https://example.com/foo'); | ||
}); | ||
it('License at file check', function() { | ||
var data = license('See license in LICENSE.md'); | ||
assert.equal(data, 'Custom: LICENSE.md'); | ||
data = license('SEE LICENSE IN LICENSE.md'); | ||
assert.equal(data, 'Custom: LICENSE.md'); | ||
}); | ||
it('Check for null', function() { | ||
@@ -82,0 +118,0 @@ var data = license('this is empty, hi'); |
@@ -124,16 +124,21 @@ var assert = require('assert'), | ||
describe('should parse local with unknown and excludes', function() { | ||
var output; | ||
before(function(done) { | ||
function parseAndExclude(parsePath, licenses, result) { | ||
return function(done) { | ||
checker.init({ | ||
start: path.join(__dirname, '../'), | ||
exclude: "MIT, ISC" | ||
start: path.join(__dirname, parsePath), | ||
exclude: licenses | ||
}, function(err, filtered) { | ||
output = filtered; | ||
result.output = filtered; | ||
done(); | ||
}); | ||
}); | ||
}; | ||
} | ||
describe('should parse local with unknown and excludes', function() { | ||
var result={}; | ||
before(parseAndExclude('../', "MIT, ISC", result)); | ||
it('should exclude MIT and ISC licensed modules from results', function() { | ||
var excluded = true; | ||
var output = result.output; | ||
Object.keys(output).forEach(function(item) { | ||
@@ -148,7 +153,53 @@ if (output[item].licenses && (output[item].licenses === "MIT" || output[item].licenses === "ISC")) | ||
describe('should parse local with excludes containing commas', function() { | ||
var result={}; | ||
before(parseAndExclude('./fixtures/excludeWithComma', "Apache License\\, Version 2.0", result)); | ||
it('should exclude a license with a comma from the list', function() { | ||
var excluded = true; | ||
var output = result.output; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && output[item].licenses === "Apache License, Version 2.0") | ||
excluded = false; | ||
}); | ||
assert.ok(excluded); | ||
}); | ||
}); | ||
describe('should parse local with BSD excludes', function() { | ||
var result={}; | ||
before(parseAndExclude('./fixtures/excludeBSD', "BSD", result)); | ||
it('should exclude BSD-3-Clause', function() { | ||
var excluded = true; | ||
var output = result.output; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && output[item].licenses === "BSD-3-Clause") | ||
excluded = false; | ||
}); | ||
assert.ok(excluded); | ||
}); | ||
}); | ||
describe('should parse local with Public Domain excludes', function() { | ||
var result={}; | ||
before(parseAndExclude('./fixtures/excludePublicDomain', "Public Domain", result)); | ||
it('should exclude Public Domain', function() { | ||
var excluded = true; | ||
var output = result.output; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && output[item].licenses === "Public Domain") | ||
excluded = false; | ||
}); | ||
assert.ok(excluded); | ||
}); | ||
}); | ||
describe('should parse local and handle private modules', function() { | ||
var output; | ||
before(function(done) { | ||
checker.init({ | ||
start: path.join(__dirname, './fixtures'), | ||
exclude: "Apache License\\, Version 2.0" | ||
start: path.join(__dirname, './fixtures/privateModule'), | ||
}, function(err, filtered) { | ||
@@ -160,12 +211,55 @@ output = filtered; | ||
it('should exclude a license with a comma from the list', function() { | ||
var excluded = true; | ||
it('should reconise private modules', function() { | ||
var privateModule = false; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && output[item].licenses === "Apache License, Version 2.0") | ||
excluded = false; | ||
if (output[item].licenses && output[item].licenses.indexOf("UNLICENSED") >=0) { | ||
privateModule = true; | ||
} | ||
}); | ||
assert.ok(excluded); | ||
assert.ok(privateModule); | ||
}); | ||
}); | ||
describe('should treat URLs as custom licenses', function() { | ||
var output; | ||
before(function(done) { | ||
checker.init({ | ||
start: path.join(__dirname, './fixtures/custom-license-url') | ||
}, function(err, filtered) { | ||
output = filtered; | ||
done(); | ||
}); | ||
}); | ||
it('should recognise a custom license at a url', function() { | ||
var foundCustomLicense = false; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && (output[item].licenses === "Custom: http://example.com/dummy-license")) | ||
foundCustomLicense = true; | ||
}); | ||
assert.ok(foundCustomLicense); | ||
}); | ||
}); | ||
describe('should treat file references as custom licenses', function() { | ||
var output; | ||
before(function(done) { | ||
checker.init({ | ||
start: path.join(__dirname, './fixtures/custom-license-file') | ||
}, function(err, filtered) { | ||
output = filtered; | ||
done(); | ||
}); | ||
}); | ||
it('should recognise a custom license in a file', function() { | ||
var foundCustomLicense = false; | ||
Object.keys(output).forEach(function(item) { | ||
if (output[item].licenses && (output[item].licenses === "Custom: MY-LICENSE.md")) | ||
foundCustomLicense = true; | ||
}); | ||
assert.ok(foundCustomLicense); | ||
}); | ||
}); | ||
describe('error handler', function() { | ||
@@ -412,3 +506,3 @@ it('should init without errors', function(done) { | ||
it('as files', function() { | ||
var out = path.join(require('os').tmpDir(), 'lc'), | ||
var out = path.join(require('os').tmpdir(), 'lc'), | ||
files; | ||
@@ -415,0 +509,0 @@ checker.asFiles({ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
102587
29
1322
166
10
+ Addedspdx-correct@^2.0.3
+ Addedspdx-satisfies@^0.1.3
+ Addedspdx-compare@0.1.2(transitive)
+ Addedspdx-correct@2.0.4(transitive)
+ Addedspdx-expression-parse@1.0.42.0.2(transitive)
+ Addedspdx-license-ids@2.0.1(transitive)
+ Addedspdx-ranges@1.0.1(transitive)
+ Addedspdx-satisfies@0.1.3(transitive)