Вы когда-нибудь задумывались о том, чтобы иметь сторонний лицензионный документ, содержащий лицензию на все производственные зависимости вашего проекта JavaScript? Это действительно необходимо?

Внезапный ответ будет нет, мы предполагаем, что зависимости, используемые в наших проектах, загружаются через npm или yarn, и у нас есть разрешение на их упаковку и распространение по своему усмотрению. Однако, когда вы просматриваете лицензионные документы некоторых из этих зависимостей, вы можете пересмотреть свой мыслительный процесс.

Вот несколько отрывков из нескольких лицензионных документов.

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of works must retain the original copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the original copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the W3C nor the names of its contributors may be used to endorse or promote products derived from this work without specific prior written permission.

Это как-то изменило ваше мнение? Всегда лучше создать сторонний лицензионный документ со сводкой использованных лицензий, а также соответствующими лицензионными документами. Однако вручную скопировать лицензионный документ и проверить тип лицензии для каждой зависимости довольно обременительно.

Теперь давайте посмотрим, как этого добиться с помощью простого сценария JS узла.

Мы будем использовать модули npm license-checker и fs-extra в нашем скрипте. Следовательно, установите их глобально и потребуйте их в новом файле js, как показано ниже.

const checker = require(‘/globalPath/license-checker’);
const fs = require(‘/globalPath/fs-extra’);

Определите путь к лицензионному документу, который будет сгенерирован.

const file = ‘./Product-License.txt';

Инициализируйте функцию checker.init с необходимой конфигурацией, обратившись к документации по проверке лицензий.

var licenses = [];
checker.init(
  {
    start: "/Documents/TestApp",
    production: true
  },
  function(err, json) {
    if (err) {
      console.log(err); //Handle error
    } else {
      copyLicenseToText(json); //The sorted json data
    }
  }
);

Присвойте значения массиву лицензий и сгруппируйте элементы по типу лицензии.

function copyLicenseToText(json) {
  Object.keys(json).forEach(function(key) {
    let obj = json[key];
    obj.module = key;
    licenses.push(obj);
  });
  licenses = licenses.filter(item => !isMarkDown(item.licenseFile));
  licenses = groupBy(licenses, l => l.licenses);
  printLicenseSummary();
  printLicenseDetails();
}

Распечатайте сводку лицензий с лицензиями, сгруппированными и отсортированными по типу.

function printLicenseSummary() {
  Object.keys(licenses).forEach(function(key) {
    let licenseCategory = licenses[key];
    fs.outputFile(file, licenseCategory, function(err) {
      //creates directory structure if doesn't exist
      if (err) return console.error(err);
      appendToLicenseFile(file, "\n\n-------------------\n");
      appendToLicenseFile(file, `${key} - License Summary\n`);
      appendToLicenseFile(file, "--------------------\n \n");
      licenseCategory.map(license => {
        appendToLicenseFile(file, `${license.module} \n`);
      });
    });
  });
}

Просмотрите массив лицензий и добавьте в документ каждый файл лицензий.

function printLicenseDetails() {
  Object.keys(licenses).forEach(function(key) {
    let licenseCategory = licenses[key];
    fs.outputFile(file, licenseCategory, function(err) {
      //creates directory structure if doesn't exist
      if (err) return console.error(err);
      appendToLicenseFile(file, "\n\n----------------------\n");
      appendToLicenseFile(file, `${key} - License Details \n`);
      appendToLicenseFile(file, "------------------------\n \n");
    });
    licenseCategory.map(license => {
      copyLicense(license);
    });
  });
}
function groupBy(xs, f) {
  return xs.reduce(
    (r, v, i, a, k = f(v)) => ((r[k] || (r[k] = [])).push(v), r),
    {}
  );
}
function copyLicense(item) {
  try {
    if (item.licenseFile && !isMarkDown(item.licenseFile)) {
      let licenseFile = fs.readFileSync(`${item.licenseFile}`, "utf8");
      fs.outputFile(file, licenseFile, function(err) {
        //creates directory structure if doesn't exist
        if (err) return console.error(err);
        appendToLicenseFile(file, "\n\n----------------------\n");
        appendToLicenseFile(file, `${item.module} - `);
        appendToLicenseFile(file, `${item.licenses} \n`);
        appendToLicenseFile(file, "-----------------------\n \n");
        appendToLicenseFile(file, licenseFile);
      });
    }
  } catch (err) {
    console.error(err);
  }
}
function appendToLicenseFile(file, data) {
  fs.appendFile(file, data, err => {
    if (err) throw err;
  });
}
function isMarkDown(filename) {
  if (filename) {
    var pathArray = filename.split("/");
    if (pathArray.length) {
      let lastName = pathArray[pathArray.length - 1];
      if (
        (lastName && lastName.toUpperCase() == "README.MD") ||
        (lastName && lastName.toUpperCase() == "README.MARKDOWN")
      ) {
        return true;
      }
    }
  }
  return false;
}

Запустите файл в узле, как показано ниже.

node filename.js

Теперь у нас есть консолидированный лицензионный документ третьей стороны с лицензиями, сгруппированными по типу, а также с добавлением каждого лицензионного документа к одному единственному документу. Созданный лицензионный документ можно добавить в корневую папку версии для развертывания. Образец сформированного документа можно увидеть ниже.

Спасибо за прочтение. Хорошего дня !!