mirror of
https://github.com/contentful/skills.git
synced 2026-09-14 20:17:03 +08:00
445 lines
18 KiB
JavaScript
445 lines
18 KiB
JavaScript
import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
const ROOT = process.cwd();
|
|
const PACKAGE_JSON_PATH = path.join(ROOT, 'package.json');
|
|
const NOTICE_PATH = path.join(ROOT, 'NOTICE');
|
|
const LICENSES_DIR = path.join(ROOT, 'licenses');
|
|
|
|
const LICENSE_TEMPLATES = {
|
|
'0BSD': `BSD Zero Clause License
|
|
|
|
Copyright (c) YEAR COPYRIGHT HOLDER
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
`,
|
|
'Apache-2.0': `Apache License
|
|
Version 2.0, January 2004
|
|
http://www.apache.org/licenses/
|
|
|
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
|
|
1. Definitions.
|
|
|
|
"License" shall mean the terms and conditions for use, reproduction,
|
|
and distribution as defined by Sections 1 through 9 of this document.
|
|
|
|
"Licensor" shall mean the copyright owner or entity authorized by
|
|
the copyright owner that is granting the License.
|
|
|
|
"Legal Entity" shall mean the union of the acting entity and all
|
|
other entities that control, are controlled by, or are under common
|
|
control with that entity. For the purposes of this definition,
|
|
"control" means (i) the power, direct or indirect, to cause the
|
|
direction or management of such entity, whether by contract or
|
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
|
|
"You" (or "Your") shall mean an individual or Legal Entity
|
|
exercising permissions granted by this License.
|
|
|
|
"Source" form shall mean the preferred form for making modifications,
|
|
including but not limited to software source code, documentation
|
|
source, and configuration files.
|
|
|
|
"Object" form shall mean any form resulting from mechanical
|
|
transformation or translation of a Source form, including but
|
|
not limited to compiled object code, generated documentation,
|
|
and conversions to other media types.
|
|
|
|
"Work" shall mean the work of authorship, whether in Source or
|
|
Object form, made available under the License, as indicated by a
|
|
copyright notice that is included in or attached to the work
|
|
(an example is provided in the Appendix below).
|
|
|
|
"Derivative Works" shall mean any work, whether in Source or Object
|
|
form, that is based on (or derived from) the Work and for which the
|
|
editorial revisions, annotations, elaborations, or other modifications
|
|
represent, as a whole, an original work of authorship. For the purposes
|
|
of this License, Derivative Works shall not include works that remain
|
|
separable from, or merely link (or bind by name) to the interfaces of,
|
|
the Work and Derivative Works thereof.
|
|
|
|
"Contribution" shall mean any work of authorship, including
|
|
the original version of the Work and any modifications or additions
|
|
to that Work or Derivative Works thereof, that is intentionally
|
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
or by an individual or Legal Entity authorized to submit on behalf of
|
|
the copyright owner. For the purposes of this definition, "submitted"
|
|
means any form of electronic, verbal, or written communication sent
|
|
to the Licensor or its representatives, including but not limited to
|
|
communication on electronic mailing lists, source code control systems,
|
|
and issue tracking systems that are managed by, or on behalf of, the
|
|
Licensor for the purpose of discussing and improving the Work, but
|
|
excluding communication that is conspicuously marked or otherwise
|
|
designated in writing by the copyright owner as "Not a Contribution."
|
|
|
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
on behalf of whom a Contribution has been received by Licensor and
|
|
subsequently incorporated within the Work.
|
|
|
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
this License, each Contributor hereby grants to You a perpetual,
|
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
copyright license to reproduce, prepare Derivative Works of,
|
|
publicly display, publicly perform, sublicense, and distribute the
|
|
Work and such Derivative Works in Source or Object form.
|
|
|
|
3. Grant of Patent License. Subject to the terms and conditions of
|
|
this License, each Contributor hereby grants to You a perpetual,
|
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
(except as stated in this section) patent license to make, have made,
|
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
where such license applies only to those patent claims licensable
|
|
by such Contributor that are necessarily infringed by their
|
|
Contribution(s) alone or by combination of their Contribution(s)
|
|
with the Work to which such Contribution(s) was submitted. If You
|
|
institute patent litigation against any entity (including a
|
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
or a Contribution incorporated within the Work constitutes direct
|
|
or contributory patent infringement, then any patent licenses
|
|
granted to You under this License for that Work shall terminate
|
|
as of the date such litigation is filed.
|
|
|
|
4. Redistribution. You may reproduce and distribute copies of the
|
|
Work or Derivative Works thereof in any medium, with or without
|
|
modifications, and in Source or Object form, provided that You
|
|
meet the following conditions:
|
|
|
|
(a) You must give any other recipients of the Work or
|
|
Derivative Works a copy of this License; and
|
|
|
|
(b) You must cause any modified files to carry prominent notices
|
|
stating that You changed the files; and
|
|
|
|
(c) You must retain, in the Source form of any Derivative Works
|
|
that You distribute, all copyright, patent, trademark, and
|
|
attribution notices from the Source form of the Work,
|
|
excluding those notices that do not pertain to any part of
|
|
the Derivative Works; and
|
|
|
|
(d) If the Work includes a "NOTICE" text file as part of its
|
|
distribution, then any Derivative Works that You distribute must
|
|
include a readable copy of the attribution notices contained
|
|
within such NOTICE file, excluding those notices that do not
|
|
pertain to any part of the Derivative Works, in at least one
|
|
of the following places: within a NOTICE text file distributed
|
|
as part of the Derivative Works; within the Source form or
|
|
documentation, if provided along with the Derivative Works; or,
|
|
within a display generated by the Derivative Works, if and
|
|
wherever such third-party notices normally appear. The contents
|
|
of the NOTICE file are for informational purposes only and
|
|
do not modify the License. You may add Your own attribution
|
|
notices within Derivative Works that You distribute, alongside
|
|
or as an addendum to the NOTICE text from the Work, provided
|
|
that such additional attribution notices cannot be construed
|
|
as modifying the License.
|
|
|
|
You may add Your own copyright statement to Your modifications and
|
|
may provide additional or different license terms and conditions
|
|
for use, reproduction, or distribution of Your modifications, or
|
|
for any such Derivative Works as a whole, provided Your use,
|
|
reproduction, and distribution of the Work otherwise complies with
|
|
the conditions stated in this License.
|
|
|
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
any Contribution intentionally submitted for inclusion in the Work
|
|
by You to the Licensor shall be under the terms and conditions of
|
|
this License, without any additional terms or conditions.
|
|
Notwithstanding the above, nothing herein shall supersede or modify
|
|
the terms of any separate license agreement you may have executed
|
|
with Licensor regarding such Contributions.
|
|
|
|
6. Trademarks. This License does not grant permission to use the trade
|
|
names, trademarks, service marks, or product names of the Licensor,
|
|
except as required for reasonable and customary use in describing the
|
|
origin of the Work and reproducing the content of the NOTICE file.
|
|
|
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
agreed to in writing, Licensor provides the Work (and each
|
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
implied, including, without limitation, any warranties or conditions
|
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
appropriateness of using or redistributing the Work and assume any
|
|
risks associated with Your exercise of permissions under this License.
|
|
|
|
8. Limitation of Liability. In no event and under no legal theory,
|
|
whether in tort (including negligence), contract, or otherwise,
|
|
unless required by applicable law (such as deliberate and grossly
|
|
negligent acts) or agreed to in writing, shall any Contributor be
|
|
liable to You for damages, including any direct, indirect, special,
|
|
incidental, or consequential damages of any character arising as a
|
|
result of this License or out of the use or inability to use the
|
|
Work (including but not limited to damages for loss of goodwill,
|
|
work stoppage, computer failure or malfunction, or any and all
|
|
other commercial damages or losses), even if such Contributor
|
|
has been advised of the possibility of such damages.
|
|
|
|
9. Accepting Warranty or Additional Liability. While redistributing
|
|
the Work or Derivative Works thereof, You may choose to offer,
|
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
or other liability obligations and/or rights consistent with this
|
|
License. However, in accepting such obligations, You may act only
|
|
on Your own behalf and on Your sole responsibility, not on behalf
|
|
of any other Contributor, and only if You agree to indemnify,
|
|
defend, and hold each Contributor harmless for any liability
|
|
incurred by, or claims asserted against, such Contributor by reason
|
|
of your accepting any such warranty or additional liability.
|
|
`,
|
|
ISC: `ISC License
|
|
|
|
Copyright (c) YEAR, COPYRIGHT HOLDER
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
`,
|
|
MIT: `MIT License
|
|
|
|
Copyright (c) YEAR COPYRIGHT HOLDER
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
`,
|
|
};
|
|
|
|
const LICENSE_OVERRIDES = {
|
|
'@contentful/skill-kit': 'MIT',
|
|
};
|
|
|
|
function toNpmUrl(name) {
|
|
return `https://www.npmjs.com/package/${name}`;
|
|
}
|
|
|
|
function normalizeRepositoryUrl(url) {
|
|
if (!url) {
|
|
return undefined;
|
|
}
|
|
|
|
return String(url).replace(/^git\+/, '').replace(/\.git$/, '');
|
|
}
|
|
|
|
function readLicenseString(pkgJson) {
|
|
if (typeof pkgJson.license === 'string' && pkgJson.license.trim()) {
|
|
return pkgJson.license.trim();
|
|
}
|
|
|
|
if (pkgJson.license && typeof pkgJson.license.type === 'string' && pkgJson.license.type.trim()) {
|
|
return pkgJson.license.type.trim();
|
|
}
|
|
|
|
if (Array.isArray(pkgJson.licenses) && pkgJson.licenses.length > 0) {
|
|
const list = pkgJson.licenses
|
|
.map((license) => {
|
|
if (typeof license === 'string') {
|
|
return license;
|
|
}
|
|
|
|
if (license && typeof license.type === 'string') {
|
|
return license.type;
|
|
}
|
|
|
|
return undefined;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
if (list.length > 0) {
|
|
return list.join(' OR ');
|
|
}
|
|
}
|
|
|
|
return 'UNKNOWN';
|
|
}
|
|
|
|
async function readDependencyMetadata(name) {
|
|
const dependencyPackageJsonPath = path.join(ROOT, 'node_modules', ...name.split('/'), 'package.json');
|
|
|
|
try {
|
|
const raw = await readFile(dependencyPackageJsonPath, 'utf8');
|
|
const pkg = JSON.parse(raw);
|
|
|
|
const detectedLicense = readLicenseString(pkg);
|
|
|
|
return {
|
|
name,
|
|
license: LICENSE_OVERRIDES[name] || detectedLicense,
|
|
url: pkg.homepage || normalizeRepositoryUrl(pkg.repository?.url) || toNpmUrl(name),
|
|
};
|
|
} catch {
|
|
return {
|
|
name,
|
|
license: LICENSE_OVERRIDES[name] || 'UNKNOWN',
|
|
url: toNpmUrl(name),
|
|
};
|
|
}
|
|
}
|
|
|
|
async function collectDependencies(depMap) {
|
|
const names = Object.keys(depMap || {}).sort((a, b) => a.localeCompare(b));
|
|
const items = [];
|
|
|
|
for (const name of names) {
|
|
items.push(await readDependencyMetadata(name));
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
function renderDependencies(items) {
|
|
if (items.length === 0) {
|
|
return 'None\n';
|
|
}
|
|
|
|
return `${items
|
|
.map((item) => `${item.name}\n License: ${item.license}\n ${item.url} [npmjs.com]`)
|
|
.join('\n')}\n`;
|
|
}
|
|
|
|
function renderNotice(runtimeDependencies, developmentDependencies) {
|
|
return `This project includes the following third-party open-source software components. Each is provided under its respective license.
|
|
|
|
Runtime Dependencies (Production)
|
|
|
|
${renderDependencies(runtimeDependencies)}
|
|
|
|
Development Dependencies
|
|
|
|
${renderDependencies(developmentDependencies)}
|
|
|
|
Each component is used in accordance with its open-source license. The
|
|
applicable license texts are included in this repository under the
|
|
licenses/ directory.
|
|
|
|
For more details, please refer to the LICENSE file for this project.
|
|
`;
|
|
}
|
|
|
|
function normalizeLicenseId(license) {
|
|
if (!license) {
|
|
return 'UNKNOWN';
|
|
}
|
|
|
|
const normalized = license.trim();
|
|
|
|
if (!normalized || normalized.includes(' OR ') || normalized.includes(' AND ')) {
|
|
return 'UNKNOWN';
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
|
|
function renderUnknownLicenseText(packages) {
|
|
const list = packages.sort((a, b) => a.localeCompare(b)).map((name) => `- ${name}`).join('\n');
|
|
|
|
return `Some dependencies do not expose a machine-readable SPDX license in their package metadata.
|
|
|
|
The following direct dependencies are currently marked as UNKNOWN:
|
|
|
|
${list}
|
|
|
|
Please review these packages manually and update this file if needed.
|
|
`;
|
|
}
|
|
|
|
async function updateLicenseFiles(allDependencies) {
|
|
await mkdir(LICENSES_DIR, { recursive: true });
|
|
|
|
const existingFiles = await readdir(LICENSES_DIR);
|
|
const licensesToPackages = new Map();
|
|
|
|
for (const dependency of allDependencies) {
|
|
const id = normalizeLicenseId(dependency.license);
|
|
if (!licensesToPackages.has(id)) {
|
|
licensesToPackages.set(id, []);
|
|
}
|
|
licensesToPackages.get(id).push(dependency.name);
|
|
}
|
|
|
|
const targetFileNames = new Set();
|
|
const writes = [];
|
|
|
|
for (const [licenseId, packages] of licensesToPackages.entries()) {
|
|
const fileName = `${licenseId}.txt`;
|
|
targetFileNames.add(fileName);
|
|
|
|
let content;
|
|
|
|
if (licenseId === 'UNKNOWN') {
|
|
content = renderUnknownLicenseText(packages);
|
|
} else if (LICENSE_TEMPLATES[licenseId]) {
|
|
content = LICENSE_TEMPLATES[licenseId];
|
|
} else {
|
|
content = `No built-in template is available for ${licenseId}.\n\nPlease add the full license text for this SPDX id manually.\n`;
|
|
}
|
|
|
|
writes.push(writeFile(path.join(LICENSES_DIR, fileName), content, 'utf8'));
|
|
}
|
|
|
|
await Promise.all(writes);
|
|
|
|
const deletes = existingFiles
|
|
.filter((fileName) => !targetFileNames.has(fileName))
|
|
.map((fileName) => rm(path.join(LICENSES_DIR, fileName)));
|
|
|
|
await Promise.all(deletes);
|
|
}
|
|
|
|
async function main() {
|
|
const packageJsonRaw = await readFile(PACKAGE_JSON_PATH, 'utf8');
|
|
const packageJson = JSON.parse(packageJsonRaw);
|
|
|
|
const runtimeDependencies = await collectDependencies(packageJson.dependencies);
|
|
const developmentDependencies = await collectDependencies(packageJson.devDependencies);
|
|
const allDependencies = [...runtimeDependencies, ...developmentDependencies];
|
|
|
|
const notice = renderNotice(runtimeDependencies, developmentDependencies);
|
|
await writeFile(NOTICE_PATH, notice, 'utf8');
|
|
|
|
await updateLicenseFiles(allDependencies);
|
|
|
|
const uniqueLicenses = [...new Set(allDependencies.map((dependency) => normalizeLicenseId(dependency.license)))].sort();
|
|
|
|
console.log(`Found ${runtimeDependencies.length} direct runtime dependencies`);
|
|
console.log(`Found ${developmentDependencies.length} direct development dependencies`);
|
|
console.log(`Found ${uniqueLicenses.length} unique license types: ${uniqueLicenses.join(', ')}`);
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|