146 lines
3.7 KiB
JavaScript
Executable File
146 lines
3.7 KiB
JavaScript
Executable File
#!/usr/bin/env -S node -r esbin
|
|
import fs from "node:fs"
|
|
import { resolve } from "node:path"
|
|
import { load } from "js-yaml"
|
|
|
|
process.chdir(resolve(__dirname, ".."))
|
|
|
|
const candidates = [
|
|
"master/LICENSE",
|
|
"master/LICENCE",
|
|
"master/LICENSE.md",
|
|
"master/license.md",
|
|
"main/LICENSE.txt",
|
|
]
|
|
|
|
async function getLicense(repo: string) {
|
|
for (const candidate of candidates) {
|
|
const path = `https://raw.githubusercontent.com/${repo}/${candidate}`
|
|
const res = await fetch(path)
|
|
if (!res.ok) continue
|
|
const text = await res.text()
|
|
return text
|
|
}
|
|
throw new Error(`Could not find license for ${repo}`)
|
|
}
|
|
|
|
async function getSDPXLicense(license: string) {
|
|
const path = `https://raw.githubusercontent.com/spdx/license-list-data/main/text/${license}.txt`
|
|
const res = await fetch(path)
|
|
if (!res.ok) throw new Error(`Could not find license ${license}`)
|
|
const text = await res.text()
|
|
return text
|
|
}
|
|
|
|
function getVendorLicenses() {
|
|
return fs
|
|
.readdirSync("src/vendor")
|
|
.map(name => ({ name, path: `src/vendor/${name}/LICENSE` }))
|
|
.filter(({ path }) => fs.existsSync(path))
|
|
.map(({ name, path }) => [name, fs.readFileSync(path, "utf8")])
|
|
}
|
|
|
|
async function getPackageLicense(pkg: string) {
|
|
const files = ["LICENSE", "LICENCE", "license.md"]
|
|
for (const file of files) {
|
|
const path = `node_modules/${pkg}/${file}`
|
|
if (fs.existsSync(path)) {
|
|
return fs.readFileSync(path, "utf8")
|
|
}
|
|
}
|
|
|
|
const pkgJson = JSON.parse(fs.readFileSync(`node_modules/${pkg}/package.json`, "utf8"))
|
|
const licenseName = pkgJson.license as string
|
|
if (!licenseName) throw new Error(`Could not find license for ${pkg}`)
|
|
|
|
return getSDPXLicense(licenseName)
|
|
}
|
|
|
|
function getPackageLicenses() {
|
|
const {
|
|
dependencies = {},
|
|
devDependencies = {},
|
|
peerDependencies = {},
|
|
} = JSON.parse(fs.readFileSync("package.json", "utf8"))
|
|
const packages = Object.keys({
|
|
...dependencies,
|
|
...devDependencies,
|
|
...peerDependencies,
|
|
})
|
|
return Promise.all(packages.map(async pkg => [pkg, await getPackageLicense(pkg)]))
|
|
}
|
|
|
|
class Licenses {
|
|
libs = new Set<string>()
|
|
|
|
constructor(readonly json: Record<string, string>) {}
|
|
|
|
set(name: string, license: string) {
|
|
this.libs.add(name)
|
|
this.json[name] = license
|
|
}
|
|
|
|
async setIfAbsent(name: string, license: () => Promise<string>) {
|
|
if (!this.json[name]) {
|
|
const text = await license()
|
|
this.set(name, text)
|
|
}
|
|
}
|
|
|
|
assign(others: Record<string, string>) {
|
|
for (const [name, license] of Object.entries(others)) {
|
|
this.set(name, license)
|
|
}
|
|
}
|
|
|
|
purge() {
|
|
for (const name of Object.keys(this.json)) {
|
|
if (!this.libs.has(name)) {
|
|
delete this.json[name]
|
|
}
|
|
}
|
|
}
|
|
|
|
toJSON() {
|
|
return this.json
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const outPath = "src/generated/licenses.json"
|
|
if (!fs.existsSync(outPath)) {
|
|
fs.writeFileSync(outPath, "{}")
|
|
}
|
|
const res = new Licenses(
|
|
JSON.parse(fs.readFileSync(outPath, "utf8")) as Record<string, string>,
|
|
)
|
|
const config = load(fs.readFileSync("src/licenses.yml", "utf8")) as {
|
|
github: string[]
|
|
licenses: { [name: string]: string }
|
|
}
|
|
|
|
// res.set("archive", await getSPLicense("AGPL-3.0-or-later"));
|
|
for (const repo of config.github) {
|
|
await res.setIfAbsent(repo, () => getLicense(repo))
|
|
}
|
|
for (const [name, license] of Object.entries(config.licenses)) {
|
|
await res.setIfAbsent(name, () => getSDPXLicense(license))
|
|
}
|
|
res.assign(Object.fromEntries(getVendorLicenses()))
|
|
res.assign(Object.fromEntries(await getPackageLicenses()))
|
|
res.purge()
|
|
|
|
fs.writeFileSync(
|
|
outPath,
|
|
JSON.stringify(
|
|
Object.fromEntries(
|
|
Object.entries(res.toJSON()).sort(([a], [b]) => a.localeCompare(b)),
|
|
),
|
|
null,
|
|
2,
|
|
) + "\n",
|
|
)
|
|
}
|
|
|
|
void main()
|