.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / spdx-correct / index.js
1 /*
2 Copyright spdx-correct.js contributors
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 var parse = require('spdx-expression-parse')
17 var spdxLicenseIds = require('spdx-license-ids')
18
19 function valid (string) {
20   try {
21     parse(string)
22     return true
23   } catch (error) {
24     return false
25   }
26 }
27
28 // Common transpositions of license identifier acronyms
29 var transpositions = [
30   ['APGL', 'AGPL'],
31   ['Gpl', 'GPL'],
32   ['GLP', 'GPL'],
33   ['APL', 'Apache'],
34   ['ISD', 'ISC'],
35   ['GLP', 'GPL'],
36   ['IST', 'ISC'],
37   ['Claude', 'Clause'],
38   [' or later', '+'],
39   [' International', ''],
40   ['GNU', 'GPL'],
41   ['GUN', 'GPL'],
42   ['+', ''],
43   ['GNU GPL', 'GPL'],
44   ['GNU/GPL', 'GPL'],
45   ['GNU GLP', 'GPL'],
46   ['GNU General Public License', 'GPL'],
47   ['Gnu public license', 'GPL'],
48   ['GNU Public License', 'GPL'],
49   ['GNU GENERAL PUBLIC LICENSE', 'GPL'],
50   ['MTI', 'MIT'],
51   ['Mozilla Public License', 'MPL'],
52   ['Universal Permissive License', 'UPL'],
53   ['WTH', 'WTF'],
54   ['-License', '']
55 ]
56
57 var TRANSPOSED = 0
58 var CORRECT = 1
59
60 // Simple corrections to nearly valid identifiers.
61 var transforms = [
62   // e.g. 'mit'
63   function (argument) {
64     return argument.toUpperCase()
65   },
66   // e.g. 'MIT '
67   function (argument) {
68     return argument.trim()
69   },
70   // e.g. 'M.I.T.'
71   function (argument) {
72     return argument.replace(/\./g, '')
73   },
74   // e.g. 'Apache- 2.0'
75   function (argument) {
76     return argument.replace(/\s+/g, '')
77   },
78   // e.g. 'CC BY 4.0''
79   function (argument) {
80     return argument.replace(/\s+/g, '-')
81   },
82   // e.g. 'LGPLv2.1'
83   function (argument) {
84     return argument.replace('v', '-')
85   },
86   // e.g. 'Apache 2.0'
87   function (argument) {
88     return argument.replace(/,?\s*(\d)/, '-$1')
89   },
90   // e.g. 'GPL 2'
91   function (argument) {
92     return argument.replace(/,?\s*(\d)/, '-$1.0')
93   },
94   // e.g. 'Apache Version 2.0'
95   function (argument) {
96     return argument
97       .replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2')
98   },
99   // e.g. 'Apache Version 2'
100   function (argument) {
101     return argument
102       .replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2.0')
103   },
104   // e.g. 'ZLIB'
105   function (argument) {
106     return argument[0].toUpperCase() + argument.slice(1)
107   },
108   // e.g. 'MPL/2.0'
109   function (argument) {
110     return argument.replace('/', '-')
111   },
112   // e.g. 'Apache 2'
113   function (argument) {
114     return argument
115       .replace(/\s*V\s*(\d)/, '-$1')
116       .replace(/(\d)$/, '$1.0')
117   },
118   // e.g. 'GPL-2.0', 'GPL-3.0'
119   function (argument) {
120     if (argument.indexOf('3.0') !== -1) {
121       return argument + '-or-later'
122     } else {
123       return argument + '-only'
124     }
125   },
126   // e.g. 'GPL-2.0-'
127   function (argument) {
128     return argument + 'only'
129   },
130   // e.g. 'GPL2'
131   function (argument) {
132     return argument.replace(/(\d)$/, '-$1.0')
133   },
134   // e.g. 'BSD 3'
135   function (argument) {
136     return argument.replace(/(-| )?(\d)$/, '-$2-Clause')
137   },
138   // e.g. 'BSD clause 3'
139   function (argument) {
140     return argument.replace(/(-| )clause(-| )(\d)/, '-$3-Clause')
141   },
142   // e.g. 'New BSD license'
143   function (argument) {
144     return argument.replace(/\b(Modified|New|Revised)(-| )?BSD((-| )License)?/i, 'BSD-3-Clause')
145   },
146   // e.g. 'Simplified BSD license'
147   function (argument) {
148     return argument.replace(/\bSimplified(-| )?BSD((-| )License)?/i, 'BSD-2-Clause')
149   },
150   // e.g. 'Free BSD license'
151   function (argument) {
152     return argument.replace(/\b(Free|Net)(-| )?BSD((-| )License)?/i, 'BSD-2-Clause-$1BSD')
153   },
154   // e.g. 'Clear BSD license'
155   function (argument) {
156     return argument.replace(/\bClear(-| )?BSD((-| )License)?/i, 'BSD-3-Clause-Clear')
157   },
158   // e.g. 'Old BSD License'
159   function (argument) {
160     return argument.replace(/\b(Old|Original)(-| )?BSD((-| )License)?/i, 'BSD-4-Clause')
161   },
162   // e.g. 'BY-NC-4.0'
163   function (argument) {
164     return 'CC-' + argument
165   },
166   // e.g. 'BY-NC'
167   function (argument) {
168     return 'CC-' + argument + '-4.0'
169   },
170   // e.g. 'Attribution-NonCommercial'
171   function (argument) {
172     return argument
173       .replace('Attribution', 'BY')
174       .replace('NonCommercial', 'NC')
175       .replace('NoDerivatives', 'ND')
176       .replace(/ (\d)/, '-$1')
177       .replace(/ ?International/, '')
178   },
179   // e.g. 'Attribution-NonCommercial'
180   function (argument) {
181     return 'CC-' +
182       argument
183         .replace('Attribution', 'BY')
184         .replace('NonCommercial', 'NC')
185         .replace('NoDerivatives', 'ND')
186         .replace(/ (\d)/, '-$1')
187         .replace(/ ?International/, '') +
188       '-4.0'
189   }
190 ]
191
192 var licensesWithVersions = spdxLicenseIds
193   .map(function (id) {
194     var match = /^(.*)-\d+\.\d+$/.exec(id)
195     return match
196       ? [match[0], match[1]]
197       : [id, null]
198   })
199   .reduce(function (objectMap, item) {
200     var key = item[1]
201     objectMap[key] = objectMap[key] || []
202     objectMap[key].push(item[0])
203     return objectMap
204   }, {})
205
206 var licensesWithOneVersion = Object.keys(licensesWithVersions)
207   .map(function makeEntries (key) {
208     return [key, licensesWithVersions[key]]
209   })
210   .filter(function identifySoleVersions (item) {
211     return (
212       // Licenses has just one valid version suffix.
213       item[1].length === 1 &&
214       item[0] !== null &&
215       // APL will be considered Apache, rather than APL-1.0
216       item[0] !== 'APL'
217     )
218   })
219   .map(function createLastResorts (item) {
220     return [item[0], item[1][0]]
221   })
222
223 licensesWithVersions = undefined
224
225 // If all else fails, guess that strings containing certain substrings
226 // meant to identify certain licenses.
227 var lastResorts = [
228   ['UNLI', 'Unlicense'],
229   ['WTF', 'WTFPL'],
230   ['2 CLAUSE', 'BSD-2-Clause'],
231   ['2-CLAUSE', 'BSD-2-Clause'],
232   ['3 CLAUSE', 'BSD-3-Clause'],
233   ['3-CLAUSE', 'BSD-3-Clause'],
234   ['AFFERO', 'AGPL-3.0-or-later'],
235   ['AGPL', 'AGPL-3.0-or-later'],
236   ['APACHE', 'Apache-2.0'],
237   ['ARTISTIC', 'Artistic-2.0'],
238   ['Affero', 'AGPL-3.0-or-later'],
239   ['BEER', 'Beerware'],
240   ['BOOST', 'BSL-1.0'],
241   ['BSD', 'BSD-2-Clause'],
242   ['CDDL', 'CDDL-1.1'],
243   ['ECLIPSE', 'EPL-1.0'],
244   ['FUCK', 'WTFPL'],
245   ['GNU', 'GPL-3.0-or-later'],
246   ['LGPL', 'LGPL-3.0-or-later'],
247   ['GPLV1', 'GPL-1.0-only'],
248   ['GPL-1', 'GPL-1.0-only'],
249   ['GPLV2', 'GPL-2.0-only'],
250   ['GPL-2', 'GPL-2.0-only'],
251   ['GPL', 'GPL-3.0-or-later'],
252   ['MIT +NO-FALSE-ATTRIBS', 'MITNFA'],
253   ['MIT', 'MIT'],
254   ['MPL', 'MPL-2.0'],
255   ['X11', 'X11'],
256   ['ZLIB', 'Zlib']
257 ].concat(licensesWithOneVersion)
258
259 var SUBSTRING = 0
260 var IDENTIFIER = 1
261
262 var validTransformation = function (identifier) {
263   for (var i = 0; i < transforms.length; i++) {
264     var transformed = transforms[i](identifier).trim()
265     if (transformed !== identifier && valid(transformed)) {
266       return transformed
267     }
268   }
269   return null
270 }
271
272 var validLastResort = function (identifier) {
273   var upperCased = identifier.toUpperCase()
274   for (var i = 0; i < lastResorts.length; i++) {
275     var lastResort = lastResorts[i]
276     if (upperCased.indexOf(lastResort[SUBSTRING]) > -1) {
277       return lastResort[IDENTIFIER]
278     }
279   }
280   return null
281 }
282
283 var anyCorrection = function (identifier, check) {
284   for (var i = 0; i < transpositions.length; i++) {
285     var transposition = transpositions[i]
286     var transposed = transposition[TRANSPOSED]
287     if (identifier.indexOf(transposed) > -1) {
288       var corrected = identifier.replace(
289         transposed,
290         transposition[CORRECT]
291       )
292       var checked = check(corrected)
293       if (checked !== null) {
294         return checked
295       }
296     }
297   }
298   return null
299 }
300
301 module.exports = function (identifier, options) {
302   options = options || {}
303   var upgrade = options.upgrade === undefined ? true : !!options.upgrade
304   function postprocess (value) {
305     return upgrade ? upgradeGPLs(value) : value
306   }
307   var validArugment = (
308     typeof identifier === 'string' &&
309     identifier.trim().length !== 0
310   )
311   if (!validArugment) {
312     throw Error('Invalid argument. Expected non-empty string.')
313   }
314   identifier = identifier.trim()
315   if (valid(identifier)) {
316     return postprocess(identifier)
317   }
318   var noPlus = identifier.replace(/\+$/, '').trim()
319   if (valid(noPlus)) {
320     return postprocess(noPlus)
321   }
322   var transformed = validTransformation(identifier)
323   if (transformed !== null) {
324     return postprocess(transformed)
325   }
326   transformed = anyCorrection(identifier, function (argument) {
327     if (valid(argument)) {
328       return argument
329     }
330     return validTransformation(argument)
331   })
332   if (transformed !== null) {
333     return postprocess(transformed)
334   }
335   transformed = validLastResort(identifier)
336   if (transformed !== null) {
337     return postprocess(transformed)
338   }
339   transformed = anyCorrection(identifier, validLastResort)
340   if (transformed !== null) {
341     return postprocess(transformed)
342   }
343   return null
344 }
345
346 function upgradeGPLs (value) {
347   if ([
348     'GPL-1.0', 'LGPL-1.0', 'AGPL-1.0',
349     'GPL-2.0', 'LGPL-2.0', 'AGPL-2.0',
350     'LGPL-2.1'
351   ].indexOf(value) !== -1) {
352     return value + '-only'
353   } else if ([
354     'GPL-1.0+', 'GPL-2.0+', 'GPL-3.0+',
355     'LGPL-2.0+', 'LGPL-2.1+', 'LGPL-3.0+',
356     'AGPL-1.0+', 'AGPL-3.0+'
357   ].indexOf(value) !== -1) {
358     return value.replace(/\+$/, '-or-later')
359   } else if (['GPL-3.0', 'LGPL-3.0', 'AGPL-3.0'].indexOf(value) !== -1) {
360     return value + '-or-later'
361   } else {
362     return value
363   }
364 }