buildLicenses.ts

 1import * as fs from "fs"
 2import toml from "toml"
 3import { schemeMeta } from "./colorSchemes"
 4import { Meta, Verification } from "./themes/common/colorScheme"
 5import https from "https"
 6import crypto from "crypto"
 7
 8const accepted_licenses_file = `${__dirname}/../../script/licenses/zed-licenses.toml`
 9
10// Use the cargo-about configuration file as the source of truth for supported licenses.
11function parseAcceptedToml(file: string): string[] {
12    let buffer = fs.readFileSync(file).toString()
13
14    let obj = toml.parse(buffer)
15
16    if (!Array.isArray(obj.accepted)) {
17        throw Error("Accepted license source is malformed")
18    }
19
20    return obj.accepted
21}
22
23function checkLicenses(schemeMeta: Meta[], licenses: string[]) {
24    for (let meta of schemeMeta) {
25        // FIXME: Add support for conjuctions and conditions
26        if (licenses.indexOf(meta.license.SPDX) < 0) {
27            throw Error(
28                `License for theme ${meta.name} (${meta.license.SPDX}) is not supported`
29            )
30        }
31    }
32}
33
34function getLicenseText(
35    schemeMeta: Meta[],
36    callback: (meta: Meta, license_text: string) => void
37) {
38    for (let meta of schemeMeta) {
39        if (typeof meta.license.license_text == "string") {
40            callback(meta, meta.license.license_text)
41        } else {
42            let license_text_obj: Verification = meta.license.license_text
43            // The following copied from the example code on nodejs.org:
44            // https://nodejs.org/api/http.html#httpgetoptions-callback
45            https
46                .get(license_text_obj.https_url, (res) => {
47                    const { statusCode } = res
48
49                    if (statusCode < 200 || statusCode >= 300) {
50                        throw new Error(
51                            `Failed to fetch license for: ${meta.name}, Status Code: ${statusCode}`
52                        )
53                    }
54
55                    res.setEncoding("utf8")
56                    let rawData = ""
57                    res.on("data", (chunk) => {
58                        rawData += chunk
59                    })
60                    res.on("end", () => {
61                        const hash = crypto
62                            .createHash("sha256")
63                            .update(rawData)
64                            .digest("hex")
65                        if (license_text_obj.license_checksum == hash) {
66                            callback(meta, rawData)
67                        } else {
68                            throw Error(
69                                `Checksum for ${meta.name} did not match file downloaded from ${license_text_obj.https_url}`
70                            )
71                        }
72                    })
73                })
74                .on("error", (e) => {
75                    throw e
76                })
77        }
78    }
79}
80
81function writeLicense(schemeMeta: Meta, text: String) {
82    process.stdout.write(
83        `## [${schemeMeta.name}](${schemeMeta.url})\n\n${text}\n********************************************************************************\n\n`
84    )
85}
86
87const accepted_licenses = parseAcceptedToml(accepted_licenses_file)
88checkLicenses(schemeMeta, accepted_licenses)
89
90getLicenseText(schemeMeta, (meta, text) => {
91    writeLicense(meta, text)
92})