@dev-build-deploy/reuse-it
Version:
(ReUSE) Copyright and License management library
234 lines (233 loc) • 8.62 kB
JavaScript
;
/*
SPDX-FileCopyrightText: 2023 Kevin de Jong <monkaii@hotmail.com>
SPDX-License-Identifier: MIT
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpdxFile = exports.DEP5_FILE_PATH = void 0;
const commentIt = __importStar(require("@dev-build-deploy/comment-it"));
const debian = __importStar(require("@dev-build-deploy/dep5-it"));
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs"));
const parser = __importStar(require("../parser"));
/** @internal */
exports.DEP5_FILE_PATH = ".reuse/dep5";
const fileTypes = [
"SOURCE",
"BINARY",
"ARCHIVE",
"APPLICATION",
"AUDIO",
"IMAGE",
"TEXT",
"VIDEO",
"DOCUMENTATION",
"SPDX",
"OTHER",
];
/**
* SPDX File
* @member SPDXID The SPDX ID of the file
* @member annotations Annotations
* @member checksum Checksums
* @member comment Comments
* @member contributors Contributors
* @member fileName The file name
* @member fileTypes The file types
* @member licenseComments License comments
* @member licenseConcluded License concluded
* @member licenseInfoInFiles License information in files
* @member noticeText Notices
* @member attributionTexts Attribution texts
*/
class SpdxFile {
constructor(fileName) {
this.checksums = [];
this.fileContributors = []; // 0..*
this.fileTypes = []; // 0..*
this.licenseConcluded = "NOASSERTION";
this.licenseInfoInFiles = ["NOASSERTION"];
this.attributionTexts = []; // 0..*
this.fileName = fileName.startsWith("./") ? fileName : `./${fileName}`;
this.SPDXID = `SPDXRef-${crypto.createHash("SHA1").update(fileName).digest("hex")}`;
// Generate the checksum
const contents = fs.readFileSync(this.fileName, "utf-8");
this.checksums = [
{
algorithm: "SHA1",
checksumValue: crypto.createHash("SHA1").update(contents).digest("hex")
}
];
}
/**
* Create a SPDX file from the provided file path, and update it with information from (in order of precedence):
*
* 1. The Debian Configuration file
* 2. The .license file
* 3. File tags provided in comment blocks in the file
*
* @param file The file path to create the SPDX file from
* @returns The SPDX file
*/
static async fromFile(file) {
/**
* Updates the SPDX file with information the Debian Configuration file
* @param file The SPDX file to update
* @returns The updated SPDX file
*/
function parseDebianFile(file) {
const dep5 = debian.DebianCopyright.fromFile(exports.DEP5_FILE_PATH);
if (dep5.header.copyright) {
file.copyrightText = dep5.header.copyright;
}
if (dep5.header.license) {
file.licenseInfoInFiles = [dep5.header.license];
}
const stanza = dep5.getFileStanza(file.fileName.replace("./", ""));
if (stanza) {
if (stanza.copyright) {
file.copyrightText = stanza.copyright;
}
if (stanza.license) {
file.licenseInfoInFiles = [stanza.license];
}
}
return file;
}
/**
* Update the SPDX file with information provided in the plain text file
* @param file The SPDX file to update
* @returns The updated SPDX file
*/
async function parsePlainFile(source, file) {
const content = fs.readFileSync(source, "utf-8");
const comment = {
type: "multiline",
format: { start: "", end: "" },
contents: []
};
let index = 0;
for (const line of content.split("\n")) {
comment.contents.push({
line: index,
column: { start: 0, end: line.length },
value: line
});
index += 1;
}
let ignore = false;
for await (const token of parser.extractData(comment)) {
if (token.type === "ignore") {
ignore = token.data.startsWith("Start");
}
if (ignore)
continue;
file = await updateFromToken(token, file);
}
return file;
}
/**
* Updates the SPDX file with information provided as File tags
* @param file The SPDX file to update
* @returns The updated SPDX file
*/
async function parseFile(file) {
let ignore = false;
for await (const comment of commentIt.extractComments(file.fileName)) {
for await (const token of parser.extractData(comment)) {
if (token.type === "ignore") {
ignore = token.data.startsWith("Start");
}
if (ignore)
continue;
file = await updateFromToken(token, file);
}
}
return file;
}
/**
* Parses the SPDX File and ReUSE tokens from the provided comment
* @param comment Comment to parse
* @param file SPDX File to update
* @returns The updated SPDX file
*/
async function updateFromToken(token, file) {
switch (token.type) {
case "attributionText":
file.attributionTexts.push(token.data);
break;
case "comment":
file.comment = token.data;
break;
case "contributor":
file.fileContributors.push(token.data);
break;
case "licenseComments":
file.licenseComments = token.data;
break;
case "licenseConcluded":
file.licenseConcluded = token.data;
break;
case "copyright":
file.copyrightText = token.data;
break;
case "notice":
file.noticeText = token.data;
break;
case "type":
file.fileTypes.push(token.data);
break;
case "licenseInfoInFile":
case "license": {
if (file.licenseInfoInFiles.includes("NOASSERTION")) {
file.licenseInfoInFiles = [token.data];
}
else {
file.licenseInfoInFiles.push(token.data);
}
break;
}
}
return file;
}
let spdxFile = new SpdxFile(file);
if (fs.existsSync(exports.DEP5_FILE_PATH)) {
spdxFile = parseDebianFile(spdxFile);
}
if (fs.existsSync(`${file}.license`)) {
spdxFile = await parsePlainFile(`${file}.license`, spdxFile);
}
if (commentIt.isSupported(file)) {
spdxFile = await parseFile(spdxFile);
}
else {
// Fallback to plain text file parsing in case we cannot parse the file comment blocks.
spdxFile = await parsePlainFile(file, spdxFile);
}
return spdxFile;
}
}
exports.SpdxFile = SpdxFile;