mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-09-13 16:36:17 +00:00
Auto-generate third-party license notices (#370)
Closes #294 Closes #371
This commit is contained in:
parent
208e4bbba3
commit
fc7d3aa457
8 changed files with 306 additions and 14 deletions
|
@ -1,6 +1,19 @@
|
|||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const path = require("path");
|
||||
const { unlink } = require("fs");
|
||||
|
||||
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
|
||||
const LicenseCheckerWebpackPlugin = require("license-checker-webpack-plugin");
|
||||
|
||||
let rustLicenses = [];
|
||||
let debugMode = false;
|
||||
try {
|
||||
// eslint-disable-next-line global-require, import/extensions, import/no-unresolved
|
||||
rustLicenses = require("./rust-licenses");
|
||||
} catch (_) {
|
||||
// Rust licenses are not generated by Cargo About except in release mode (`npm run build`)
|
||||
debugMode = true;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
lintOnSave: "warning",
|
||||
|
@ -18,7 +31,7 @@ module.exports = {
|
|||
(Plugin) =>
|
||||
new Plugin({
|
||||
crateDirectory: path.resolve(__dirname, "wasm"),
|
||||
// Remove when this issue is resolved https://github.com/wasm-tool/wasm-pack-plugin/issues/93
|
||||
// Remove when this issue is resolved: https://github.com/wasm-tool/wasm-pack-plugin/issues/93
|
||||
outDir: path.resolve(__dirname, "wasm/pkg"),
|
||||
watchDirectories: [
|
||||
path.resolve(__dirname, "../editor"),
|
||||
|
@ -30,6 +43,22 @@ module.exports = {
|
|||
)
|
||||
.end();
|
||||
|
||||
// License Checker Webpack Plugin validates the license compatibility of all dependencies which are compiled into the webpack bundle
|
||||
// It also writes the third-party license notices to a file which is displayed in the application
|
||||
// https://github.com/microsoft/license-checker-webpack-plugin
|
||||
config
|
||||
.plugin("license-checker")
|
||||
.use(LicenseCheckerWebpackPlugin)
|
||||
.init(
|
||||
(Plugin) =>
|
||||
new Plugin({
|
||||
allow: "(Apache-2.0 OR BSD-2-Clause OR BSD-3-Clause OR MIT)",
|
||||
emitError: true,
|
||||
outputFilename: "third-party-licenses.txt",
|
||||
outputWriter: formatThirdPartyLicenses,
|
||||
})
|
||||
);
|
||||
|
||||
// Vue SVG Loader enables importing .svg files into .vue single-file components and using them directly in the HTML
|
||||
// https://vue-svg-loader.js.org/
|
||||
config.module
|
||||
|
@ -47,3 +76,97 @@ module.exports = {
|
|||
.end();
|
||||
},
|
||||
};
|
||||
|
||||
function formatThirdPartyLicenses(jsLicenses) {
|
||||
// Remove the HTML character encoding caused by Handlebars
|
||||
const licenses = rustLicenses.map((rustLicense) => ({
|
||||
licenseName: htmlDecode(rustLicense.licenseName),
|
||||
licenseText: htmlDecode(rustLicense.licenseText),
|
||||
packages: rustLicense.packages.map((package) => ({
|
||||
name: htmlDecode(package.name),
|
||||
version: htmlDecode(package.version),
|
||||
author: htmlDecode(package.author).replace(/\[(.*), \]/, "$1"),
|
||||
repository: htmlDecode(package.repository),
|
||||
})),
|
||||
}));
|
||||
|
||||
// Augment the imported Rust license list with the provided JS license list
|
||||
jsLicenses.dependencies.forEach((jsLicense) => {
|
||||
const { name, version, author, repository, licenseName, licenseText } = jsLicense;
|
||||
|
||||
// Remove the `git+` or `git://` prefix and `.git` suffix
|
||||
const repo = repository ? repository.replace(/^.*(github.com\/.*?\/.*?)(?:.git)/, "https://$1") : repository;
|
||||
|
||||
const matchedLicense = licenses.find((license) => license.licenseName.trim() === licenseName.trim() && license.licenseText.trim() === licenseText.trim());
|
||||
|
||||
const packages = { name, version, author, repository: repo };
|
||||
if (matchedLicense) matchedLicense.packages.push(packages);
|
||||
else licenses.push({ licenseName, licenseText, packages: [packages] });
|
||||
});
|
||||
|
||||
// Sort the licenses, and the packages using each license, alphabetically
|
||||
licenses.sort((a, b) => a.licenseName.localeCompare(b.licenseName));
|
||||
licenses.forEach((license) => {
|
||||
license.packages.sort((a, b) => a.name.localeCompare(b.name));
|
||||
});
|
||||
|
||||
// Generate the formatted text file
|
||||
let formattedLicenseNotice = "THIRD-PARTY SOFTWARE LICENSE NOTICES\n\n";
|
||||
if (debugMode) formattedLicenseNotice += "WARNING: Licenses for Rust packages are excluded in debug mode to improve performance — do not release without their inclusion!\n\n";
|
||||
|
||||
licenses.forEach((license) => {
|
||||
let packagesWithSameLicense = "";
|
||||
license.packages.forEach((package) => {
|
||||
const { name, version, author, repository } = package;
|
||||
packagesWithSameLicense += `${name} ${version}${author ? ` - ${author}` : ""}${repository ? ` - ${repository}` : ""}\n`;
|
||||
});
|
||||
formattedLicenseNotice += `--------------------------------------------------------------------------------
|
||||
|
||||
The following packages are licensed under the terms of the ${license.licenseName} license:
|
||||
|
||||
${packagesWithSameLicense}
|
||||
|
||||
${license.licenseText}
|
||||
|
||||
`;
|
||||
});
|
||||
|
||||
// Clean up by deleting the `rust-licenses.js` Rust licenses data file generated by Cargo About
|
||||
unlink("./rust-licenses.js", (_) => _);
|
||||
|
||||
return formattedLicenseNotice;
|
||||
}
|
||||
|
||||
const htmlEntities = {
|
||||
nbsp: " ",
|
||||
copy: "©",
|
||||
reg: "®",
|
||||
lt: "<",
|
||||
gt: ">",
|
||||
amp: "&",
|
||||
apos: "'",
|
||||
// eslint-disable-next-line quotes
|
||||
quot: '"',
|
||||
};
|
||||
|
||||
function htmlDecode(str) {
|
||||
if (!str) return str;
|
||||
|
||||
return str.replace(/&([^;]+);/g, (entity, entityCode) => {
|
||||
let match;
|
||||
|
||||
if (entityCode in htmlEntities) {
|
||||
return htmlEntities[entityCode];
|
||||
}
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
if ((match = entityCode.match(/^#x([\da-fA-F]+)$/))) {
|
||||
return String.fromCharCode(parseInt(match[1], 16));
|
||||
}
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
if ((match = entityCode.match(/^#(\d+)$/))) {
|
||||
// eslint-disable-next-line no-bitwise
|
||||
return String.fromCharCode(~~match[1]);
|
||||
}
|
||||
return entity;
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue