1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
import * as path from 'path';
import * as fs from 'fs';
import { program } from 'commander';
import { execSync } from 'child_process';
import { EOL } from 'os';
type Licenses = Record<string, License>;
interface License {
licenses: string;
repository: string;
publisher: string;
email: string;
url: string;
path: string;
licenseFile: string;
}
async function main() {
program.option('-o, --output <string>', 'Path to output file');
program.option('-d, --dir <string>', 'Path to target extension root');
program.option('-e, --exclude <string>', 'Exclude packages');
program.parse(process.argv);
const options = program.opts();
const outputFile = options.output as string;
const exclude = options.exclude as string;
const excludeList = exclude.split(',').map((excluded) => excluded.trim());
console.log('Generating third-party licenses...');
const targetExtensionRoot = options.dir as string;
const output = execSync('npx license-checker --production --json', {
cwd: targetExtensionRoot,
encoding: 'utf-8'
});
const outputJSON = JSON.parse(output) as Licenses;
const thirdPartyLicensesFile =
outputFile && outputFile !== ''
? outputFile
: path.resolve(targetExtensionRoot, 'ThirdPartyNotices.txt');
fs.rmSync(thirdPartyLicensesFile, { force: true });
const append = (str: string) => {
fs.appendFileSync(thirdPartyLicensesFile, str);
};
const appendLicense = (license: string) => {
const normalizedLicense = license.replace(/\r?\n/g, EOL);
const lines = normalizedLicense.split(EOL).map((line) => line.trimEnd());
append(lines.join(EOL));
};
const initialText = `Third-Party Notices${EOL}${EOL}This file contains the licenses for third-party software used in this product.${EOL}`;
append(initialText);
const entries = Object.entries(outputJSON);
console.log(`Found ${entries.length} third-party dependencies`);
for (const [name, license] of entries.sort()) {
if (excludeList.some((excluded) => name.includes(excluded))) {
continue;
}
append(EOL);
append(
`---------------------------------------------------------${EOL}${EOL}`
);
const version = name.split('@').pop();
const nameWithoutVersion = name.replace(`@${version}`, '');
const nameWithoutVersionAndPublisher = nameWithoutVersion.split('/').pop();
append(
`${nameWithoutVersionAndPublisher} ${version} - ${license.licenses}${EOL}`
);
append(`${license.repository}#readme${EOL}${EOL}`);
if (
!license.licenseFile ||
!license.licenseFile.toLocaleLowerCase().includes('license')
) {
const possibleLicenseFileNames = [
'license',
'license.md',
'license.txt',
'LICENSE',
'LICENSE.md',
'LICENSE.txt',
'License.txt',
'LICENSE.TXT'
];
const repo = license.repository.replace(
'github.com',
'raw.githubusercontent.com'
);
const possibleBranches = ['main', 'master'];
let found = false;
for (const possibleLicenseFileName of possibleLicenseFileNames) {
for (const possibleBranch of possibleBranches) {
const response = await fetch(
`${repo}/${possibleBranch}/${possibleLicenseFileName}`
);
if (response.ok) {
const licenseFile = await response.text();
appendLicense(licenseFile);
found = true;
break;
}
}
}
if (!found) {
throw new Error(`Could not find license file for ${name} in ${repo}`);
}
} else {
const licenseFile = fs.readFileSync(license.licenseFile, 'utf-8');
appendLicense(licenseFile);
}
append(
`${EOL}---------------------------------------------------------${EOL}`
);
}
console.log('Third-party licenses generated successfully');
}
void main();
|