index.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. var licenseIDs = require('spdx-license-ids');
  2. function valid(string) {
  3. return licenseIDs.indexOf(string) > -1;
  4. }
  5. // Common transpositions of license identifier acronyms
  6. var transpositions = [
  7. ['APGL', 'AGPL'],
  8. ['Gpl', 'GPL'],
  9. ['GLP', 'GPL'],
  10. ['APL', 'Apache'],
  11. ['ISD', 'ISC'],
  12. ['GLP', 'GPL'],
  13. ['IST', 'ISC'],
  14. ['Claude', 'Clause'],
  15. [' or later', '+'],
  16. [' International', ''],
  17. ['GNU', 'GPL'],
  18. ['GUN', 'GPL'],
  19. ['+', ''],
  20. ['GNU GPL', 'GPL'],
  21. ['GNU/GPL', 'GPL'],
  22. ['GNU GLP', 'GPL'],
  23. ['GNU General Public License', 'GPL'],
  24. ['Gnu public license', 'GPL'],
  25. ['GNU Public License', 'GPL'],
  26. ['GNU GENERAL PUBLIC LICENSE', 'GPL'],
  27. ['MTI', 'MIT'],
  28. ['Mozilla Public License', 'MPL'],
  29. ['WTH', 'WTF'],
  30. ['-License', '']
  31. ];
  32. var TRANSPOSED = 0;
  33. var CORRECT = 1;
  34. // Simple corrections to nearly valid identifiers.
  35. var transforms = [
  36. // e.g. 'mit'
  37. function(argument) {
  38. return argument.toUpperCase();
  39. },
  40. // e.g. 'MIT '
  41. function(argument) {
  42. return argument.trim();
  43. },
  44. // e.g. 'M.I.T.'
  45. function(argument) {
  46. return argument.replace(/\./g, '');
  47. },
  48. // e.g. 'Apache- 2.0'
  49. function(argument) {
  50. return argument.replace(/\s+/g, '');
  51. },
  52. // e.g. 'CC BY 4.0''
  53. function(argument) {
  54. return argument.replace(/\s+/g, '-');
  55. },
  56. // e.g. 'LGPLv2.1'
  57. function(argument) {
  58. return argument.replace('v', '-');
  59. },
  60. // e.g. 'Apache 2.0'
  61. function(argument) {
  62. return argument.replace(/,?\s*(\d)/, '-$1');
  63. },
  64. // e.g. 'GPL 2'
  65. function(argument) {
  66. return argument.replace(/,?\s*(\d)/, '-$1.0');
  67. },
  68. // e.g. 'Apache Version 2.0'
  69. function(argument) {
  70. return argument.replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2');
  71. },
  72. // e.g. 'Apache Version 2'
  73. function(argument) {
  74. return argument.replace(/,?\s*(V\.|v\.|V|v|Version|version)\s*(\d)/, '-$2.0');
  75. },
  76. // e.g. 'ZLIB'
  77. function(argument) {
  78. return argument[0].toUpperCase() + argument.slice(1);
  79. },
  80. // e.g. 'MPL/2.0'
  81. function(argument) {
  82. return argument.replace('/', '-');
  83. },
  84. // e.g. 'Apache 2'
  85. function(argument) {
  86. return argument
  87. .replace(/\s*V\s*(\d)/, '-$1')
  88. .replace(/(\d)$/, '$1.0');
  89. },
  90. // e.g. 'GPL-2.0-'
  91. function(argument) {
  92. return argument.slice(0, argument.length - 1);
  93. },
  94. // e.g. 'GPL2'
  95. function(argument) {
  96. return argument.replace(/(\d)$/, '-$1.0');
  97. },
  98. // e.g. 'BSD 3'
  99. function(argument) {
  100. return argument.replace(/(-| )?(\d)$/, '-$2-Clause');
  101. },
  102. // e.g. 'BSD clause 3'
  103. function(argument) {
  104. return argument.replace(/(-| )clause(-| )(\d)/, '-$3-Clause');
  105. },
  106. // e.g. 'BY-NC-4.0'
  107. function(argument) {
  108. return 'CC-' + argument;
  109. },
  110. // e.g. 'BY-NC'
  111. function(argument) {
  112. return 'CC-' + argument + '-4.0';
  113. },
  114. // e.g. 'Attribution-NonCommercial'
  115. function(argument) {
  116. return argument
  117. .replace('Attribution', 'BY')
  118. .replace('NonCommercial', 'NC')
  119. .replace('NoDerivatives', 'ND')
  120. .replace(/ (\d)/, '-$1')
  121. .replace(/ ?International/, '');
  122. },
  123. // e.g. 'Attribution-NonCommercial'
  124. function(argument) {
  125. return 'CC-' +
  126. argument
  127. .replace('Attribution', 'BY')
  128. .replace('NonCommercial', 'NC')
  129. .replace('NoDerivatives', 'ND')
  130. .replace(/ (\d)/, '-$1')
  131. .replace(/ ?International/, '') +
  132. '-4.0';
  133. }
  134. ];
  135. // If all else fails, guess that strings containing certain substrings
  136. // meant to identify certain licenses.
  137. var lastResorts = [
  138. ['UNLI', 'Unlicense'],
  139. ['WTF', 'WTFPL'],
  140. ['2 CLAUSE', 'BSD-2-Clause'],
  141. ['2-CLAUSE', 'BSD-2-Clause'],
  142. ['3 CLAUSE', 'BSD-3-Clause'],
  143. ['3-CLAUSE', 'BSD-3-Clause'],
  144. ['AFFERO', 'AGPL-3.0'],
  145. ['AGPL', 'AGPL-3.0'],
  146. ['APACHE', 'Apache-2.0'],
  147. ['ARTISTIC', 'Artistic-2.0'],
  148. ['Affero', 'AGPL-3.0'],
  149. ['BEER', 'Beerware'],
  150. ['BOOST', 'BSL-1.0'],
  151. ['BSD', 'BSD-2-Clause'],
  152. ['ECLIPSE', 'EPL-1.0'],
  153. ['FUCK', 'WTFPL'],
  154. ['GNU', 'GPL-3.0'],
  155. ['LGPL', 'LGPL-3.0'],
  156. ['GPL', 'GPL-3.0'],
  157. ['MIT', 'MIT'],
  158. ['MPL', 'MPL-2.0'],
  159. ['X11', 'X11'],
  160. ['ZLIB', 'Zlib']
  161. ];
  162. var SUBSTRING = 0;
  163. var IDENTIFIER = 1;
  164. var validTransformation = function(identifier) {
  165. for (var i = 0; i < transforms.length; i++) {
  166. var transformed = transforms[i](identifier);
  167. if (transformed !== identifier && valid(transformed)) {
  168. return transformed;
  169. }
  170. }
  171. return null;
  172. };
  173. var validLastResort = function(identifier) {
  174. var upperCased = identifier.toUpperCase();
  175. for (var i = 0; i < lastResorts.length; i++) {
  176. var lastResort = lastResorts[i];
  177. if (upperCased.indexOf(lastResort[SUBSTRING]) > -1) {
  178. return lastResort[IDENTIFIER];
  179. }
  180. }
  181. return null;
  182. };
  183. var anyCorrection = function(identifier, check) {
  184. for (var i = 0; i < transpositions.length; i++) {
  185. var transposition = transpositions[i];
  186. var transposed = transposition[TRANSPOSED];
  187. if (identifier.indexOf(transposed) > -1) {
  188. var corrected = identifier.replace(
  189. transposed,
  190. transposition[CORRECT]
  191. );
  192. var checked = check(corrected);
  193. if (checked !== null) {
  194. return checked;
  195. }
  196. }
  197. }
  198. return null;
  199. };
  200. module.exports = function(identifier) {
  201. identifier = identifier.replace(/\+$/, '');
  202. if (valid(identifier)) {
  203. return identifier;
  204. }
  205. var transformed = validTransformation(identifier);
  206. if (transformed !== null) {
  207. return transformed;
  208. }
  209. transformed = anyCorrection(identifier, function(argument) {
  210. if (valid(argument)) {
  211. return argument;
  212. }
  213. return validTransformation(argument);
  214. });
  215. if (transformed !== null) {
  216. return transformed;
  217. }
  218. transformed = validLastResort(identifier);
  219. if (transformed !== null) {
  220. return transformed;
  221. }
  222. transformed = anyCorrection(identifier, validLastResort);
  223. if (transformed !== null) {
  224. return transformed;
  225. }
  226. return null;
  227. };