You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lossless-cut/script/checkLicenses.ts

97 lines
2.9 KiB
TypeScript

import { execa } from 'execa';
const { stdout } = await execa('yarn', ['licenses', 'list', '-R', '--json'], { encoding: 'utf8' });
const licensesJson: { value: string; children: Record<string, unknown> }[] = JSON.parse(`[${stdout.split('\n').join(',')}]`);
const safeLicenses: Record<string, true | string[]> = {
// These aim to remove almost all restrictions
'CC0-1.0': true,
Unlicense: true,
WTFPL: true,
'0BSD': true,
// Permissive licenses: These impose minimal requirements (mostly attribution + license notice). You can generally use them interchangeably in commercial and proprietary software.
MIT: true,
'BSD-2-Clause': true,
'BSD-3-Clause': true,
ISC: true,
Zlib: true,
'Python-2.0': true,
'BlueOak-1.0.0': true,
'MIT/X11': true,
// Permissive licenses with some conditions
'Apache-2.0': true,
// Copyleft licenses: These require that derivative works be distributed under the same license terms. They ensure that modifications remain open source.
// which is OK because LosslessCut is also GPL-2.0-only
'GPL-2.0-only': ['lossless-cut'],
// Weak copyleft licenses: These allow linking with proprietary software under certain conditions, making them more flexible than strong copyleft licenses.
'LGPL-3.0-only': true,
'LGPL-3.0-or-later': true,
'MPL-2.0': true,
// Special purpose licenses
'Hippocratic-2.1': ['@react-leaflet/core', 'react-leaflet'],
// not software licenses
'CC-BY-3.0': ['spdx-exceptions'], // eslint-plugin-unicorn
'CC-BY-4.0': ['caniuse-lite'],
// Font licenses
'OFL-1.1': true, // permissive
UNKNOWN: ['fast-shallow-equal', 'react-universal-interface', 'buffers'],
};
const unsafeLicenses = licensesJson.flatMap((l) => {
const checkLicense = (license: string) => {
const safeLicense = safeLicenses[license];
if (safeLicense === true) {
return true;
}
if (safeLicense == null) {
return false;
}
return Object.keys(l.children).every((pkg) => (
safeLicense.some((safeLicensePackage) => pkg.startsWith(safeLicensePackage))
));
};
// e.g. "(BSD-2-Clause OR MIT OR Apache-2.0)"
// e.g. "(LGPL-3.0-only AND MIT)"
const trimmed = l.value.replace(/^\(/, '').replace(/\)$/, '');
const isOr = l.value.includes(' OR ');
const isAnd = l.value.includes(' AND ');
if (isOr || isAnd) {
const licenses = trimmed.split(isOr ? ' OR ' : ' AND ').map((s) => s.trim());
if (isOr) {
return licenses.some((license) => checkLicense(license)) ? [] : [l];
}
if (isAnd) {
return licenses.every((license) => checkLicense(license)) ? [] : [l];
}
}
return checkLicense(trimmed) ? [] : [l];
});
if (unsafeLicenses.length > 0) {
console.error('Found unsafe licenses:');
console.error();
for (const l of unsafeLicenses) {
console.error(l.value);
console.error(`${Object.keys(l.children).map((v) => `- ${v}`).join('\n')}`);
console.error();
}
process.exitCode = 1;
} else {
console.log('All licenses are safe.');
}