1
- const licenseChecker = require ( 'license-checker' ) ;
1
+ require ( '../lib/bootstrap-local' ) ;
2
+
3
+ const path = require ( 'path' ) ;
4
+ const glob = require ( 'glob' ) ;
2
5
const spdxSatisfies = require ( 'spdx-satisfies' ) ;
3
- const denodeify = require ( 'denodeify' ) ;
4
- const licenseCheckerInit = denodeify ( licenseChecker . init ) ;
6
+ // TODO use logger.Logger
7
+ const logger = require ( '@ngtools/logger' ) ;
5
8
6
9
7
10
// SPDX defined licenses, see https://spdx.org/licenses/.
11
+ // TODO(hansl): confirm this list
8
12
const acceptedSpdxLicenses = [
9
13
'MIT' ,
10
14
'ISC' ,
@@ -19,59 +23,101 @@ const acceptedSpdxLicenses = [
19
23
] ;
20
24
21
25
// Name variations of SPDX licenses that some packages have.
22
- const ignoredLicenseVariations = [
23
- 'MIT*' ,
24
- 'MIT/X11' ,
25
- 'AFLv2.1' ,
26
- 'AFLv3.0' ,
27
- 'Apache-2.0' ,
28
- 'Apache2' ,
29
- 'BSD' ,
30
- 'BSD*' ,
31
- 'BSD-like' ,
32
- 'NPL' ,
33
- 'L/GPL' ,
34
- 'Public Domain'
26
+ // Licenses not included in SPDX but accepted will be converted to MIT.
27
+ // TODO(hansl): make sure all of these are ok
28
+ const licenseReplacements = [
29
+ { name : 'Apache License, Version 2.0' , replacement : 'Apache-2.0' } ,
30
+ { name : 'AFLv2.1' , replacement : 'AFL-2.1' } ,
31
+ // I guess they are kinda the same?
32
+ { name : 'BSD' , replacement : 'BSD-2-Clause' } ,
33
+ { name : 'BSD-like' , replacement : 'BSD-2-Clause' } ,
34
+ { name : 'MIT/X11' , replacement : 'MIT' } ,
35
+ // Not sure how to deal with public domain.
36
+ // http://wiki.spdx.org/view/Legal_Team/Decisions/Dealing_with_Public_Domain_within_SPDX_Files
37
+ { name : 'Public Domain' , replacement : 'MIT' }
35
38
] ;
36
39
37
40
// Specific packages to ignore, add a reason in a comment. Format: package-name@version.
41
+ // TODO(hansl): review these
38
42
const ignoredPackages = [
39
- '[email protected] ' , // old license format, lists `AFLv2.1, BSD`
40
- '[email protected] ' , // old license format, lists `MIT, Apache2`
41
- '[email protected] ' , // `Apache License, Version 2.0`, but licence-checker can't handle commas
42
- '[email protected] ' , // has a MIT license but it's not listed in package.json
43
+ '[email protected] ' , // MIT, but doesn't list it in package.json
44
+ '[email protected] ' , // Looks like MIT
45
+ '[email protected] ' , // Looks like MIT
46
+ '[email protected] ' , // Looks like MIT
47
+ '[email protected] ' , // Looks like MIT
48
+ '[email protected] ' , // Looks like MIT
49
+ '[email protected] ' , // Looks like MIT
50
+ '[email protected] ' , // BSD, but doesn't list it in package.json
51
+ '[email protected] ' , // MIT, but doesn't list it in package.json
52
+ '[email protected] ' , // MIT, license but it's not listed in package.json.
53
+ '[email protected] ' , // MIT, but doesn't list it in package.json
54
+ '[email protected] ' , // MIT, but doesn't list it in package.json
55
+ '[email protected] ' , // MIT AND Apache-2.0, but broken license field in package.json lists.
56
+ '[email protected] ' , // MIT, but doesn't list it in package.json
57
+ '[email protected] ' , // BSD, but doesn't list it in package.json
58
+ '[email protected] ' , // MIT, but doesn't list it in package.json
59
+ 'undefined@undefined' , // Test package with no name nor version.
60
+ '[email protected] ' , // Looks like MIT
43
61
] ;
44
62
45
- function testSpdx ( licenses ) {
63
+ const root = path . resolve ( __dirname , '../' ) ;
64
+
65
+ // Find all folder directly under a `node_modules` that have a package.json.
66
+ const allPackages = glob . sync ( path . join ( root , '**/node_modules/*/package.json' ) , { nodir : true } )
67
+ . map ( packageJsonPath => {
68
+ const packageJson = require ( packageJsonPath ) ;
69
+ return {
70
+ id : `${ packageJson . name } @${ packageJson . version } ` ,
71
+ path : path . dirname ( packageJsonPath ) ,
72
+ packageJson : packageJson
73
+ } ;
74
+ } )
75
+ // Figure out what kind of license the package uses.
76
+ . map ( pkg => {
77
+ let license = null ;
78
+ if ( pkg . packageJson . license ) {
79
+ // Use license field if present
80
+ if ( typeof pkg . packageJson . license === 'string' ) {
81
+ license = replace ( pkg . packageJson . license ) ;
82
+ } else if ( typeof pkg . packageJson . license === 'object' && typeof pkg . packageJson . type ) {
83
+ license = replace ( pkg . packageJson . license . type ) ;
84
+ }
85
+ } else if ( Array . isArray ( pkg . packageJson . licenses ) ) {
86
+ // If there's an (outdated) licenses array use that joined by OR.
87
+ // TODO verify multiple licenses is OR and not AND
88
+ license = pkg . packageJson . licenses
89
+ . map ( license => replace ( license . type ) )
90
+ . join ( ' OR ' ) ;
91
+ }
92
+ pkg . license = license ;
93
+ return pkg ;
94
+ } )
95
+
96
+ // Packages with bad licenses are those that neither pass SPDX nor are ignored.
97
+ const badLicensePackages = allPackages
98
+ . filter ( pkg => ! passesSpdx ( pkg . license , acceptedSpdxLicenses ) )
99
+ . filter ( pkg => ! ignoredPackages . find ( ignored => ignored === pkg . id ) ) ;
100
+
101
+ // Report packages with bad licenses
102
+ if ( badLicensePackages . length > 0 ) {
103
+ console . log ( 'Invalid package licences found:\n' ) ;
104
+ badLicensePackages . forEach ( pkg => console . log ( `${ pkg . id } (${ pkg . path } ): ${ pkg . license } ` ) ) ;
105
+ process . exit ( 1 ) ;
106
+ } else {
107
+ console . log ( 'All package licenses are valid.' ) ;
108
+ }
109
+
110
+ // Check if a license is accepted by an array of accepted licenses
111
+ function passesSpdx ( license , accepted ) {
46
112
try {
47
- return spdxSatisfies ( licenses , `(${ acceptedSpdxLicenses . join ( ' OR ' ) } )` )
113
+ return spdxSatisfies ( license , `(${ accepted . join ( ' OR ' ) } )` )
48
114
} catch ( _ ) {
49
115
return false ;
50
116
}
51
117
}
52
118
53
- // Use license-checker first, it can filter more licenses.
54
- licenseCheckerInit ( {
55
- start : './' ,
56
- exclude : acceptedSpdxLicenses . concat ( ignoredLicenseVariations ) . join ( ) ,
57
- customFormat : { name : '' , _location : '' }
58
- } )
59
- . then ( json => {
60
- let badPackages = Object . keys ( json )
61
- . map ( key => Object . assign ( { } , json [ key ] , { id : key } ) )
62
- // Then run the remaining ones through spdx-satisfies.
63
- . filter ( pkg => ! testSpdx ( pkg . licenses ) )
64
- . filter ( pkg => ! ignoredPackages . find ( ignored => ignored === pkg . id ) ) ;
65
-
66
- if ( badPackages . length > 0 ) {
67
- console . log ( 'Invalid package licences found:\n' ) ;
68
- badPackages . forEach ( pkg => console . log ( `- ${ pkg . id } (${ pkg . _location } ): ${ pkg . licenses } ` ) ) ;
69
- process . exit ( 1 ) ;
70
- } else {
71
- console . log ( 'All package licenses are valid.' ) ;
72
- }
73
- } )
74
- . catch ( err => {
75
- console . log ( err ) ;
76
- process . exit ( 1 ) ;
77
- } ) ;
119
+ // Apply license name replacement if any
120
+ function replace ( license ) {
121
+ const match = licenseReplacements . find ( rpl => rpl . name === license ) ;
122
+ return match ? match . replacement : license ;
123
+ }
0 commit comments