From dfbdeb7415779fb59a002fa489105cc92258e89e Mon Sep 17 00:00:00 2001 From: AAHAbbas <46633806+AAHAbbas@users.noreply.github.com> Date: Tue, 11 Jun 2024 15:19:05 +0200 Subject: [PATCH] fix(third-party-notices): display author information (#3185) --- .changeset/curvy-grapes-shave.md | 5 ++ .../src/output/copyright.ts | 37 ++++++++++++++ .../third-party-notices/src/output/json.ts | 42 ++-------------- .../third-party-notices/src/output/text.ts | 49 +++++++++++++------ .../test/__snapshots__/licence.test.ts.snap | 8 +-- 5 files changed, 83 insertions(+), 58 deletions(-) create mode 100644 .changeset/curvy-grapes-shave.md create mode 100644 packages/third-party-notices/src/output/copyright.ts diff --git a/.changeset/curvy-grapes-shave.md b/.changeset/curvy-grapes-shave.md new file mode 100644 index 000000000..17e67a7f9 --- /dev/null +++ b/.changeset/curvy-grapes-shave.md @@ -0,0 +1,5 @@ +--- +"@rnx-kit/third-party-notices": patch +--- + +Display attribution info if no license info is found diff --git a/packages/third-party-notices/src/output/copyright.ts b/packages/third-party-notices/src/output/copyright.ts new file mode 100644 index 000000000..e87077ae7 --- /dev/null +++ b/packages/third-party-notices/src/output/copyright.ts @@ -0,0 +1,37 @@ +import { findPackage, readPackage } from "@rnx-kit/tools-node/package"; + +export function getPackageAuthor(modulePath: string): string | undefined { + const pkgFile = findPackage(modulePath); + if (pkgFile) { + const manifest = readPackage(pkgFile); + if (manifest) { + return typeof manifest.author === "string" + ? manifest.author + : manifest.author?.name; + } + } + return undefined; +} + +export function parseCopyright( + modulePath: string, + licenseText: string | undefined, + license: string | undefined, + licenseURLs: string[] +): string { + const m = licenseText?.match(/^Copyright .*$/m); + if (!m) { + const packageAuthor = getPackageAuthor(modulePath); + if (packageAuthor) { + return packageAuthor; + } + + if (licenseURLs?.length > 0) { + return `${license} (${licenseURLs.join(" ")})`; + } + + return "No copyright notice"; + } + + return m[0].trim(); +} diff --git a/packages/third-party-notices/src/output/json.ts b/packages/third-party-notices/src/output/json.ts index ce08c900a..c2ac725bd 100644 --- a/packages/third-party-notices/src/output/json.ts +++ b/packages/third-party-notices/src/output/json.ts @@ -1,41 +1,5 @@ -import { findPackage, readPackage } from "@rnx-kit/tools-node/package"; import type { License, LicenseJSONInfo } from "../types"; - -function getPackageAuthor(modulePath: string): string | undefined { - const pkgFile = findPackage(modulePath); - if (pkgFile) { - const manifest = readPackage(pkgFile); - if (manifest) { - return typeof manifest.author === "string" - ? manifest.author - : manifest.author?.name; - } - } - return undefined; -} - -function parseCopyright( - modulePath: string, - licenseText: string | undefined, - license: string | undefined, - licenseURLs: string[] -): string { - const m = licenseText?.match(/^Copyright .*$/m); - if (!m) { - const packageAuthor = getPackageAuthor(modulePath); - if (packageAuthor) { - return packageAuthor; - } - - if (licenseURLs?.length > 0) { - return `${license} (${licenseURLs.join(" ")})`; - } - - return "No copyright notice"; - } - - return m[0].trim(); -} +import { parseCopyright } from "./copyright"; export function createLicenseJSON( licenses: License[], @@ -53,7 +17,9 @@ export function createLicenseJSON( licenseURLs, }) => { if (!license) { - throw new Error(`No license for ${name}`); + throw new Error( + `No license information found for package '${name}'. Consider filing an issue for the project to properly advertise its licence. Pass this module to the tool via '--ignoreModules ${name}' to suppress this message.` + ); } const info: LicenseJSONInfo = { name, diff --git a/packages/third-party-notices/src/output/text.ts b/packages/third-party-notices/src/output/text.ts index 10dabecc6..cc98e33e3 100644 --- a/packages/third-party-notices/src/output/text.ts +++ b/packages/third-party-notices/src/output/text.ts @@ -1,4 +1,5 @@ import type { License } from "../types"; +import { getPackageAuthor } from "./copyright"; const EOL = "\n"; const SEPARATOR = `${EOL}${EOL}========================================================================${EOL}${EOL}`; @@ -11,24 +12,40 @@ export function createLicenseFileContents( const output = preambleText ? [preambleText.join(EOL)] : []; // Emit combined license text - licenses.forEach(({ name, version, license, licenseText, licenseURLs }) => { - if (license?.toUpperCase() === "UNLICENSED") { - // Ignore unlicensed/private packages - return; - } - - if (!licenseText) { - if (!license && (!licenseURLs || licenseURLs.length === 0)) { - throw new Error( - `No license information found for package '${name}'. Consider filing an issue for the project to properly advertise its licence. Pass this module to the tool via '--ignoreModules ${name}' to suppress this message.` - ); + licenses.forEach( + ({ + name, + version, + license, + licenseText, + licenseURLs, + path: modulePath, + }) => { + if (license?.toUpperCase() === "UNLICENSED") { + // Ignore unlicensed/private packages + return; } - licenseText = `${license} (${licenseURLs.join(" ")})`; - } - const trimmedText = licenseText.replace(/\r\n|\r|\n/g, EOL).trim(); - output.push(`${name} ${version}${EOL}--${EOL}${trimmedText}`); - }); + if (!licenseText) { + if (!license && (!licenseURLs || licenseURLs.length === 0)) { + throw new Error( + `No license information found for package '${name}'. Consider filing an issue for the project to properly advertise its licence. Pass this module to the tool via '--ignoreModules ${name}' to suppress this message.` + ); + } + + const copyright = getPackageAuthor(modulePath); + + if (copyright) { + licenseText = `Copyright ${copyright}; licensed under ${license} (${licenseURLs.join(" ")})`; + } else { + licenseText = `Licensed under ${license} (${licenseURLs.join(" ")})`; + } + } + + const trimmedText = licenseText.replace(/\r\n|\r|\n/g, EOL).trim(); + output.push(`${name} ${version}${EOL}--${EOL}${trimmedText}`); + } + ); if (additionalText) { output.push(additionalText.join(EOL)); diff --git a/packages/third-party-notices/test/__snapshots__/licence.test.ts.snap b/packages/third-party-notices/test/__snapshots__/licence.test.ts.snap index 5958cdccc..5ccac6c6f 100644 --- a/packages/third-party-notices/test/__snapshots__/licence.test.ts.snap +++ b/packages/third-party-notices/test/__snapshots__/licence.test.ts.snap @@ -3,13 +3,13 @@ exports[`license createLicenseFileContents 1`] = ` "@rnx-kit/console 1.2.3-fixedVersionForTesting -- -MIT (https://spdx.org/licenses/MIT.html) +Copyright Microsoft Open Source; licensed under MIT (https://spdx.org/licenses/MIT.html) ======================================================================== metro-source-map 1.2.3-fixedVersionForTesting -- -MIT (https://spdx.org/licenses/MIT.html) +Licensed under MIT (https://spdx.org/licenses/MIT.html) ======================================================================== @@ -50,13 +50,13 @@ Preamble 2 @rnx-kit/console 1.2.3-fixedVersionForTesting -- -MIT (https://spdx.org/licenses/MIT.html) +Copyright Microsoft Open Source; licensed under MIT (https://spdx.org/licenses/MIT.html) ======================================================================== metro-source-map 1.2.3-fixedVersionForTesting -- -MIT (https://spdx.org/licenses/MIT.html) +Licensed under MIT (https://spdx.org/licenses/MIT.html) ========================================================================