Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

license-report

Package Overview
Dependencies
Maintainers
0
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

license-report - npm Package Compare versions

Comparing version 6.5.0 to 6.7.0

107

CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
## [6.5.0](https://github.com/ironSource/license-report/compare/v6.4.0...v6.5.0) (2023-10-09)
## [6.7.0](https://github.com/kessler/license-report/compare/v6.6.1...v6.7.0) (2024-09-13)

@@ -10,131 +10,130 @@

* add the configuration element 'excludeRegex' - issue [#139](https://github.com/ironSource/license-report/issues/139) ([6ce1c13](https://github.com/ironSource/license-report/commit/6ce1c1341a05cf6acd05f13c6f40e22d61bd0c61))
* use properties of object entries as custom field ([#194](https://github.com/kessler/license-report/issues/194)) ([d9519b2](https://github.com/kessler/license-report/commit/d9519b23d4cdf11c8659c28644eb4fe206df1b5a))
## [6.6.1](https://github.com/kessler/license-report/compare/v6.6.0...v6.6.1) (2024-08-02)
## [6.6.0](https://github.com/kessler/license-report/compare/v6.5.1...v6.6.0) (2024-06-23)
### Features
* change the project from 'default' to named exports ([1e526eb](https://github.com/kessler/license-report/commit/1e526eb2ebd4395a45473e588a6d3e774fc9dd0d))
## [6.5.1](https://github.com/ironSource/license-report/compare/v6.5.0...v6.5.1) (2024-04-26)
## [6.5.0](https://github.com/ironSource/license-report/compare/v6.4.0...v6.5.0) (2023-10-09)
### Features
- add the configuration element 'excludeRegex' - issue [#139](https://github.com/ironSource/license-report/issues/139) ([6ce1c13](https://github.com/ironSource/license-report/commit/6ce1c1341a05cf6acd05f13c6f40e22d61bd0c61))
### Bug Fixes
* enable selecting a single field in the output via 'fields' configuration element ([#143](https://github.com/ironSource/license-report/issues/143)) ([7486bbf](https://github.com/ironSource/license-report/commit/7486bbfcd234083da6f88df833546e01904b2dae))
* make node v16 minimal required node version ([34887d0](https://github.com/ironSource/license-report/commit/34887d0f4feb7d45e9b8e077a81554a06a1c9458))
- enable selecting a single field in the output via 'fields' configuration element ([#143](https://github.com/ironSource/license-report/issues/143)) ([7486bbf](https://github.com/ironSource/license-report/commit/7486bbfcd234083da6f88df833546e01904b2dae))
- make node v16 minimal required node version ([34887d0](https://github.com/ironSource/license-report/commit/34887d0f4feb7d45e9b8e077a81554a06a1c9458))
## [6.4.0](https://github.com/ironSource/license-report/compare/v6.3.0...v6.4.0) (2023-03-14)
### Features
* add entries from package.json defined in config.fields to output ([a31ca47](https://github.com/ironSource/license-report/commit/a31ca47f1b8246eb21c7a73c9f67c35f226f6640))
- add entries from package.json defined in config.fields to output ([a31ca47](https://github.com/ironSource/license-report/commit/a31ca47f1b8246eb21c7a73c9f67c35f226f6640))
### Bug Fixes
* issue [#126](https://github.com/ironSource/license-report/issues/126) - Error when no dependency is found with markdown output ([#127](https://github.com/ironSource/license-report/issues/127)) ([ca5590c](https://github.com/ironSource/license-report/commit/ca5590cda5a0d54d24677b8ce3dd3662388c5c7b))
* solve security issue with sub-dependency ([9f0aa72](https://github.com/ironSource/license-report/commit/9f0aa720e07648ef96fc43336de16ce621ada8cd))
- issue [#126](https://github.com/ironSource/license-report/issues/126) - Error when no dependency is found with markdown output ([#127](https://github.com/ironSource/license-report/issues/127)) ([ca5590c](https://github.com/ironSource/license-report/commit/ca5590cda5a0d54d24677b8ce3dd3662388c5c7b))
- solve security issue with sub-dependency ([9f0aa72](https://github.com/ironSource/license-report/commit/9f0aa720e07648ef96fc43336de16ce621ada8cd))
## [6.3.0](https://github.com/ironSource/license-report/compare/v6.2.0...v6.3.0) (2022-10-19)
### Features
* add Markdown formatter (solves issue [#116](https://github.com/ironSource/license-report/issues/116)) ([72eb9d8](https://github.com/ironSource/license-report/commit/72eb9d8fd74d02c457814972932acfbc0339a69b))
- add Markdown formatter (solves issue [#116](https://github.com/ironSource/license-report/issues/116)) ([72eb9d8](https://github.com/ironSource/license-report/commit/72eb9d8fd74d02c457814972932acfbc0339a69b))
## [6.2.0](https://github.com/ironSource/license-report/compare/v6.1.0...v6.2.0) (2022-10-06)
### Features
* add support for monorepos ([bb1f364](https://github.com/ironSource/license-report/commit/bb1f364925502e9890bab3a143c2523935543114))
- add support for monorepos ([bb1f364](https://github.com/ironSource/license-report/commit/bb1f364925502e9890bab3a143c2523935543114))
### Bug Fixes
* add new fields from v6.1.0 to output of cli help ([6dde8dd](https://github.com/ironSource/license-report/commit/6dde8dd5f362fcd32d43c9e2761a216eb1257c31))
- add new fields from v6.1.0 to output of cli help ([6dde8dd](https://github.com/ironSource/license-report/commit/6dde8dd5f362fcd32d43c9e2761a216eb1257c31))
## [6.1.0](https://github.com/ironSource/license-report/compare/v6.0.0...v6.1.0) (2022-07-31)
### Features
* add new optional fields with data from registry ([ead1a55](https://github.com/ironSource/license-report/commit/ead1a550d212a030e657fef71f245d2299c76d08))
- add new optional fields with data from registry ([ead1a55](https://github.com/ironSource/license-report/commit/ead1a550d212a030e657fef71f245d2299c76d08))
### Bug Fixes
* issue [#101](https://github.com/ironSource/license-report/issues/101) (config.registry without trailing slash throws an error) ([76525ed](https://github.com/ironSource/license-report/commit/76525ed1a411fc007e4ea655c17fcef042c789f8))
- issue [#101](https://github.com/ironSource/license-report/issues/101) (config.registry without trailing slash throws an error) ([76525ed](https://github.com/ironSource/license-report/commit/76525ed1a411fc007e4ea655c17fcef042c789f8))
## [6.0.0](https://github.com/ironSource/license-report/compare/v5.1.0...v6.0.0) (2022-07-07)
### ⚠ BREAKING CHANGES
* update 'got' to v12; this requires switching to esm
modules and dropping support for node versions prior to Node v14 (which
are all out of maintenance status by now).
* get the installed version, the author and the
license type from the node_modules directory instead of from
the package-lock.json file.
- update 'got' to v12; this requires switching to esm
modules and dropping support for node versions prior to Node v14 (which
are all out of maintenance status by now).
- get the installed version, the author and the
license type from the node_modules directory instead of from
the package-lock.json file.
### Bug Fixes
* add default request timeout ([fce9e05](https://github.com/ironSource/license-report/commit/fce9e051170711f680aba53e3f23003a1300af39))
* add missing fieldnames in command line help text ([d29c8a1](https://github.com/ironSource/license-report/commit/d29c8a1ebf0da0c058fb0d70c47ce2f6ab290f0a))
* return 'n/a' when no license property is found in repository data ([1ffe505](https://github.com/ironSource/license-report/commit/1ffe5055086e67646f6f1d0d9f5b9667d3564bd3))
- add default request timeout ([fce9e05](https://github.com/ironSource/license-report/commit/fce9e051170711f680aba53e3f23003a1300af39))
- add missing fieldnames in command line help text ([d29c8a1](https://github.com/ironSource/license-report/commit/d29c8a1ebf0da0c058fb0d70c47ce2f6ab290f0a))
- return 'n/a' when no license property is found in repository data ([1ffe505](https://github.com/ironSource/license-report/commit/1ffe5055086e67646f6f1d0d9f5b9667d3564bd3))
## [5.1.0](https://github.com/ironSource/license-report/compare/v5.0.2...v5.1.0) (2022-06-04)
### Features
* add support for installedFrom field ([207f167](https://github.com/ironSource/license-report/commit/207f167b4492e45f34a8554f026cdb5c97e4888b))
- add support for installedFrom field ([207f167](https://github.com/ironSource/license-report/commit/207f167b4492e45f34a8554f026cdb5c97e4888b))
### Bug Fixes
* add error handling for requests to the registry ([cb7123a](https://github.com/ironSource/license-report/commit/cb7123a055238827ed3a4d71cadff9de60e42156)), closes [#85](https://github.com/ironSource/license-report/issues/85)
* fix broken e2e tests due to changed ownership for debug-js ([25d754e](https://github.com/ironSource/license-report/commit/25d754ed342b94af01b5bc96a5692495d8d687ce))
* fix missing variable declaration ([f4a64eb](https://github.com/ironSource/license-report/commit/f4a64eb5db57e42908dacb4148f93c5be7757207))
* remove typo in error message ([2cd5475](https://github.com/ironSource/license-report/commit/2cd547517af40b4f1b72b458c6f7d8be7218c6bf))
- add error handling for requests to the registry ([cb7123a](https://github.com/ironSource/license-report/commit/cb7123a055238827ed3a4d71cadff9de60e42156)), closes [#85](https://github.com/ironSource/license-report/issues/85)
- fix broken e2e tests due to changed ownership for debug-js ([25d754e](https://github.com/ironSource/license-report/commit/25d754ed342b94af01b5bc96a5692495d8d687ce))
- fix missing variable declaration ([f4a64eb](https://github.com/ironSource/license-report/commit/f4a64eb5db57e42908dacb4148f93c5be7757207))
- remove typo in error message ([2cd5475](https://github.com/ironSource/license-report/commit/2cd547517af40b4f1b72b458c6f7d8be7218c6bf))
### [5.0.2](https://github.com/ironSource/license-report/compare/v5.0.1...v5.0.2) (2022-03-11)
### Bug Fixes
* issue [#72](https://github.com/ironSource/license-report/issues/72) (Cannot read property 'version' of undefined) ([dec72d1](https://github.com/ironSource/license-report/commit/dec72d1c5828f89219dacdd2c2e8c9b808c63142))
- issue [#72](https://github.com/ironSource/license-report/issues/72) (Cannot read property 'version' of undefined) ([dec72d1](https://github.com/ironSource/license-report/commit/dec72d1c5828f89219dacdd2c2e8c9b808c63142))
## [5.0.1](https://github.com/ironSource/license-report/compare/v5.0.0...v5.0.1) (2022-02-20)
### Features
* automatically create changelog from commit messages ([f9c1030](https://github.com/ironSource/license-report/commit/f9c103053378bb88db61715331ed8f0d208fcc95))
- automatically create changelog from commit messages ([f9c1030](https://github.com/ironSource/license-report/commit/f9c103053378bb88db61715331ed8f0d208fcc95))
### Bug Fixes
* issue [#68](https://github.com/ironSource/license-report/issues/68) - evaluate string only author field ([4498bb7](https://github.com/ironSource/license-report/commit/4498bb7f9b5f74658118ee2cd96df443e5d95383))
- issue [#68](https://github.com/ironSource/license-report/issues/68) - evaluate string only author field ([4498bb7](https://github.com/ironSource/license-report/commit/4498bb7f9b5f74658118ee2cd96df443e5d95383))
## [5.0.0](https://github.com/ironSource/license-report///compare/v5.0.0...v4.5.0) (2021-09-09)
### ⚠ BREAKING CHANGES
* installed version shows actually installed version, not value from package.json without range character
- installed version shows actually installed version, not value from package.json without range character
### Features
* Allow fetching license info from peerDependencies and optionalDependencies too with `--only=prod,dev,opt,peer`
* allow versions like "nightly" and "latest"
* securely access private npm repositories with configuration variable `--npmTokenEnvVar` and authorization header with bearer token; show warning, if `--npmTokenEnvVar` is used as a config option
* add CHANGELOG.md to make changes visible to users
- Allow fetching license info from peerDependencies and optionalDependencies too with `--only=prod,dev,opt,peer`
- allow versions like "nightly" and "latest"
- securely access private npm repositories with configuration variable `--npmTokenEnvVar` and authorization header with bearer token; show warning, if `--npmTokenEnvVar` is used as a config option
- add CHANGELOG.md to make changes visible to users
### Bug Fixes
* fixes typos in source code
* fixes sort order for `--output=table` and `--output=html`
- fixes typos in source code
- fixes sort order for `--output=table` and `--output=html`
## [4.5.0](https://github.com/ironSource/license-report/compare/v5.0.0...v4.5.0) (2022-02-19)
### Bug Fixes
* issue [#68](https://github.com/ironSource/license-report/issues/68) - evaluate string only author field ([4498bb7](https://github.com/ironSource/license-report/commit/4498bb7f9b5f74658118ee2cd96df443e5d95383))
- issue [#68](https://github.com/ironSource/license-report/issues/68) - evaluate string only author field ([4498bb7](https://github.com/ironSource/license-report/commit/4498bb7f9b5f74658118ee2cd96df443e5d95383))

@@ -8,9 +8,9 @@ #!/usr/bin/env node

import config from './lib/config.js';
import getFormatter from './lib/getFormatter.js';
import addLocalPackageData from './lib/addLocalPackageData.js';
import addPackageDataFromRepository from './lib/addPackageDataFromRepository.js';
import getDependencies from './lib/getDependencies.js';
import packageDataToReportData from './lib/packageDataToReportData.js';
import util from './lib/util.js';
import { config } from './lib/config.js';
import { getFormatter } from './lib/getFormatter.js';
import { addLocalPackageData } from './lib/addLocalPackageData.js';
import { addPackageDataFromRepository } from './lib/addPackageDataFromRepository.js';
import { getDependencies } from './lib/getDependencies.js';
import { packageDataToReportData } from './lib/packageDataToReportData.js';
import { isNullOrUndefined, helpText, readJson } from './lib/util.js';

@@ -21,56 +21,81 @@ const debug = createDebugMessages('license-report');

if (config.help) {
console.log(util.helpText)
return
console.log(helpText); // eslint-disable-line security-node/detect-crlf
return;
}
if (!config.package) {
config.package = './package.json'
config.package = './package.json';
}
if (path.extname(config.package) !== '.json') {
throw new Error('invalid package.json ' + config.package)
throw new Error('invalid package.json ' + config.package);
}
const outputFormatter = getFormatter(config.output)
const outputFormatter = getFormatter(config.output);
try {
const resolvedPackageJson = path.resolve(process.cwd(), config.package)
const resolvedPackageJson = path.resolve(process.cwd(), config.package);
debug('loading %s', resolvedPackageJson)
let packageJson
debug('loading %s', resolvedPackageJson);
let packageJson;
if (fs.existsSync(resolvedPackageJson)) {
packageJson = await util.readJson(resolvedPackageJson)
packageJson = await readJson(resolvedPackageJson);
} else {
throw new Error(`Warning: the file '${resolvedPackageJson}' is required to get installed versions of packages`)
throw new Error(
`Warning: the file '${resolvedPackageJson}' is required to get installed versions of packages`,
);
}
// Get a list of all the dependencies we want information about.
const inclusions = util.isNullOrUndefined(config.only) ? null : config.only.split(',')
const exclusions = Array.isArray(config.exclude) ? config.exclude : [config.exclude]
let exclusionRegexp
if ((config.excludeRegex !== undefined) && (typeof config.excludeRegex === 'string') && (config.excludeRegex !== '')) {
const inclusions = isNullOrUndefined(config.only)
? null
: config.only.split(',');
const exclusions = Array.isArray(config.exclude)
? config.exclude
: [config.exclude];
let exclusionRegexp;
if (
config.excludeRegex !== undefined &&
typeof config.excludeRegex === 'string' &&
config.excludeRegex !== ''
) {
try {
exclusionRegexp = new RegExp(config.excludeRegex, 'i')
// TODO how to sanitize regex pattern provided by user?
// eslint-disable-next-line security/detect-non-literal-regexp
exclusionRegexp = new RegExp(config.excludeRegex, 'i');
} catch (error) {
console.error(error.message)
exclusionRegexp = undefined
console.error(error.message);
exclusionRegexp = undefined;
}
}
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let depsIndex = getDependencies(packageJson, exclusions, inclusions, exclusionRegexp)
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let depsIndex = getDependencies(
packageJson,
exclusions,
inclusions,
exclusionRegexp,
);
const projectRootPath = path.dirname(resolvedPackageJson)
const projectRootPath = path.dirname(resolvedPackageJson);
const packagesData = await Promise.all(
depsIndex.map(async (element) => {
const localDataForPackage = await addLocalPackageData(element, projectRootPath, fieldsList)
const completeDataForPackage = await addPackageDataFromRepository(localDataForPackage)
return packageDataToReportData(completeDataForPackage, config)
})
)
const localDataForPackage = await addLocalPackageData(
element,
projectRootPath,
fieldsList,
);
const completeDataForPackage =
await addPackageDataFromRepository(localDataForPackage);
return packageDataToReportData(completeDataForPackage, config);
}),
);
console.log(outputFormatter(packagesData, config))
// eslint-disable-next-line security-node/detect-crlf
console.log(outputFormatter(packagesData, config));
} catch (e) {
console.error(e.stack)
process.exit(1)
console.error(e.stack);
process.exit(1); // eslint-disable-line n/no-process-exit
}
})();

@@ -5,5 +5,5 @@ import fs from 'node:fs';

import semver from 'semver';
import util from './util.js';
import extractAuthor from './extractAuthor.js';
import extractLicense from './extractLicense.js';
import { extractAuthor } from './extractAuthor.js';
import { extractLicense } from './extractLicense.js';
import { nestedPropertyValue, readJson } from './util.js';

@@ -21,56 +21,65 @@ const debug = createDebugMessages('license-report:addLocalPackageData');

* @param {string} projectRootPath - path of the package.json the report is generated for
* @param fields - 'fields' list from the global configuration object
* @param {string[]} fields - 'fields' list from the global configuration object
* @returns {object} element with installedVersion, author and licenseType added
*/
async function addLocalPackageData(element, projectRootPath, fields) {
const notAvailableText = 'n/a'
const exclusionList = ['installedVersion', 'author', 'licenseType']
export async function addLocalPackageData(element, projectRootPath, fields) {
const notAvailableText = 'n/a';
const exclusionList = ['installedVersion', 'author', 'licenseType'];
let projectPackageJsonPath = projectRootPath
let oldProjectPackageJsonPath = ''
let projectPackageJsonPath = projectRootPath;
let oldProjectPackageJsonPath = '';
element['installedVersion'] = notAvailableText
element['author'] = notAvailableText
element['licenseType'] = notAvailableText
element['installedVersion'] = notAvailableText;
element['author'] = notAvailableText;
element['licenseType'] = notAvailableText;
let packageFolderName
let packageFolderName;
if (element.alias.length === 0) {
packageFolderName = element.fullName
packageFolderName = element.fullName;
} else {
packageFolderName = element.alias
packageFolderName = element.alias;
}
do {
const elementPackageJsonPath = path.join(projectPackageJsonPath, 'node_modules', packageFolderName, 'package.json')
const elementPackageJsonPath = path.join(
projectPackageJsonPath,
'node_modules',
packageFolderName,
'package.json',
);
if (fs.existsSync(elementPackageJsonPath)) {
const packageJSONContent = await util.readJson(elementPackageJsonPath)
if ((packageJSONContent?.version !== undefined)) {
if(!semver.validRange(element.version) || semver.satisfies(packageJSONContent.version, element.version)) {
element['installedVersion'] = packageJSONContent.version
element['author'] = extractAuthor(packageJSONContent)
element['licenseType'] = extractLicense(packageJSONContent)
const packageJSONContent = await readJson(elementPackageJsonPath);
if (packageJSONContent?.version !== undefined) {
if (
!semver.validRange(element.version) ||
semver.satisfies(packageJSONContent.version, element.version)
) {
element['installedVersion'] = packageJSONContent.version;
element['author'] = extractAuthor(packageJSONContent);
element['licenseType'] = extractLicense(packageJSONContent);
// create entries for 'custom' fields
fields.forEach(fieldName => {
if ((element[fieldName] === undefined)
&& !(fieldName in exclusionList)
&& (packageJSONContent[fieldName] !== undefined)) {
element[fieldName] = packageJSONContent[fieldName]
fields.forEach((fieldName) => {
if (
element[fieldName] === undefined &&
!(fieldName in exclusionList)
) {
const value = nestedPropertyValue(packageJSONContent, fieldName);
if (value !== undefined) {
element[fieldName] = value;
}
}
})
break
});
break;
}
}
}
oldProjectPackageJsonPath = projectPackageJsonPath
projectPackageJsonPath = path.dirname(projectPackageJsonPath)
} while (projectPackageJsonPath !== oldProjectPackageJsonPath)
oldProjectPackageJsonPath = projectPackageJsonPath;
projectPackageJsonPath = path.dirname(projectPackageJsonPath);
} while (projectPackageJsonPath !== oldProjectPackageJsonPath);
if (element['installedVersion'] === notAvailableText) {
debug('found no package.json file for %s', element.fullName)
debug('found no package.json file for %s', element.fullName);
}
return element
return element;
}
export default addLocalPackageData;
import semver from 'semver';
import getPackageDataFromRepository from './getPackageDataFromRepository.js';
import extractLink from './extractLink.js';
import extractInstalledFrom from './extractInstalledFrom.js';
import { extractInstalledFrom } from './extractInstalledFrom.js';
import { extractLink } from './extractLink.js';
import { getPackageDataFromRepository } from './getPackageDataFromRepository.js';

@@ -9,6 +9,6 @@ /**

* @param {object} packageEntry - object with information about 1 dependency from the package.json
* @returns string in the format 'packageName@packageVersion
* @returns {string} in the format 'packageName@packageVersion
*/
function toPackageString(packageEntry) {
return packageEntry.fullName + '@' + packageEntry.version
return packageEntry.fullName + '@' + packageEntry.version;
}

@@ -20,107 +20,112 @@

* @param {object} packageEntry - object with information about 1 package with data from the local package.json added
* @returns {object} with all informations about the package
* @returns {object} with all Information about the package
*/
async function addPackageDataFromRepository(packageEntry) {
const notAvailableText = 'n/a'
let definedVersion = packageEntry.version
let author = packageEntry.author
let licenseType = packageEntry.licenseType
export async function addPackageDataFromRepository(packageEntry) {
const notAvailableText = 'n/a';
let definedVersion = packageEntry.version;
let installedVersion = packageEntry.installedVersion
if (installedVersion === undefined) {
if (definedVersion.match(/^[\^~].*/)) {
installedVersion = definedVersion.substring(1)
} else {
installedVersion = definedVersion
}
}
let installedVersion = packageEntry.installedVersion;
if (installedVersion === undefined) {
if (definedVersion.match(/^[\^~].*/)) {
installedVersion = definedVersion.substring(1);
} else {
installedVersion = definedVersion;
}
}
let json = {}
let version = ''
let link = ''
let installedFrom = ''
let latest = ''
let lastModified = ''
let json = {};
let version = '';
let link = '';
let installedFrom = '';
let latest = '';
let lastModified = '';
const fullPackageName = packageEntry.fullName
const fullPackageName = packageEntry.fullName;
// test if this is a locally installed package
const linkVersionRegex = /^(http|https|file|git|git\+ssh|git\+https|github):.+/i
if (!linkVersionRegex.test(definedVersion)) {
json = await getPackageDataFromRepository(fullPackageName)
// test if this is a locally installed package
const linkVersionRegex =
/^(http|https|file|git|git\+ssh|git\+https|github):.+/i;
if (!linkVersionRegex.test(definedVersion)) {
json = await getPackageDataFromRepository(fullPackageName);
if (json.versions) {
const versions = Object.keys(json.versions)
const installedVersionData = json.versions[installedVersion]
if (installedVersionData !== undefined) {
installedFrom = extractInstalledFrom(installedVersionData) || notAvailableText
} else {
installedFrom = notAvailableText
}
if (json.versions) {
const versions = Object.keys(json.versions);
const installedVersionData = json.versions[installedVersion];
if (installedVersionData !== undefined) {
installedFrom =
extractInstalledFrom(installedVersionData) || notAvailableText;
} else {
installedFrom = notAvailableText;
}
// Get the right remote version for this package
let localVersionSemverRange = semver.validRange(definedVersion)
if (!localVersionSemverRange) {
localVersionSemverRange = definedVersion
}
// Get the right remote version for this package
let localVersionSemverRange = semver.validRange(definedVersion);
if (!localVersionSemverRange) {
localVersionSemverRange = definedVersion;
}
// remoteVersion
version = semver.maxSatisfying(versions, localVersionSemverRange)
if ((version === null) && (json['dist-tags'] !== undefined) && (json['dist-tags'][definedVersion] !== undefined)) {
version = json['dist-tags'][definedVersion]
}
// remoteVersion
version = semver.maxSatisfying(versions, localVersionSemverRange);
if (
version === null &&
json['dist-tags'] !== undefined &&
json['dist-tags'][definedVersion] !== undefined
) {
version = json['dist-tags'][definedVersion];
}
// latestRemoteVersion
latest = notAvailableText
if ((json['dist-tags'] !== undefined) && (json['dist-tags'].latest !== undefined)) {
latest = json['dist-tags'].latest
}
// latestRemoteVersion
latest = notAvailableText;
if (
json['dist-tags'] !== undefined &&
json['dist-tags'].latest !== undefined
) {
latest = json['dist-tags'].latest;
}
// latestRemoteModified
lastModified = notAvailableText
if ((json.time !== undefined) && (json.time.modified !== undefined)) {
lastModified = json.time.modified
}
// latestRemoteModified
lastModified = notAvailableText;
if (json.time !== undefined && json.time.modified !== undefined) {
lastModified = json.time.modified;
}
// link
if (version !== null) {
const serverVersionData = json.versions[version]
link = extractLink(serverVersionData)
} else {
version = `no matching version found in registry for package '${toPackageString(packageEntry)}'`
link = notAvailableText
}
} else {
link = notAvailableText
installedFrom = notAvailableText
version = `no versions in registry for package ${fullPackageName}`
latest = notAvailableText
lastModified = notAvailableText
}
} else {
link = notAvailableText
installedFrom = packageEntry.version
definedVersion = notAvailableText
version = notAvailableText
latest = notAvailableText
lastModified = notAvailableText
}
// link
if (version !== null) {
const serverVersionData = json.versions[version];
link = extractLink(serverVersionData);
} else {
version = `no matching version found in registry for package '${toPackageString(packageEntry)}'`;
link = notAvailableText;
}
} else {
link = notAvailableText;
installedFrom = notAvailableText;
version = `no versions in registry for package ${fullPackageName}`;
latest = notAvailableText;
lastModified = notAvailableText;
}
} else {
link = notAvailableText;
installedFrom = packageEntry.version;
definedVersion = notAvailableText;
version = notAvailableText;
latest = notAvailableText;
lastModified = notAvailableText;
}
// add / modify entries in packageEntry
packageEntry.name = fullPackageName
packageEntry.link = link
packageEntry.installedFrom = installedFrom
packageEntry.definedVersion = definedVersion
packageEntry.installedVersion = installedVersion
packageEntry.remoteVersion = version.toString()
packageEntry.latestRemoteVersion = latest
packageEntry.latestRemoteModified = lastModified
packageEntry.comment = version.toString()
delete packageEntry.alias
delete packageEntry.fullName
delete packageEntry.scope
delete packageEntry.version
return packageEntry
// add / modify entries in packageEntry
packageEntry.name = fullPackageName;
packageEntry.link = link;
packageEntry.installedFrom = installedFrom;
packageEntry.definedVersion = definedVersion;
packageEntry.installedVersion = installedVersion;
packageEntry.remoteVersion = version.toString();
packageEntry.latestRemoteVersion = latest;
packageEntry.latestRemoteModified = lastModified;
packageEntry.comment = version.toString();
delete packageEntry.alias;
delete packageEntry.fullName;
delete packageEntry.scope;
delete packageEntry.version;
return packageEntry;
}
export default addPackageDataFromRepository;

@@ -10,47 +10,55 @@ /**

*/
function addPackagesToIndex(packages, packageIndex, exclusions, exclusionRegex) {
exclusions = exclusions || []
export function addPackagesToIndex(
packages,
packageIndex,
exclusions,
exclusionRegex,
) {
exclusions = exclusions || [];
// iterate over packages and prepare urls before I call the registry
for (let key in packages) {
if ((exclusions.indexOf(key) !== -1) || exclusionRegex?.test(key)) {
continue
}
// iterate over packages and prepare urls before I call the registry
for (let key in packages) {
if (exclusions.indexOf(key) !== -1 || exclusionRegex?.test(key)) {
continue;
}
let name = key
let fullName = key
let alias = ''
let version = packages[key]
if (version.startsWith('npm:')) {
alias = fullName
const aliasBase = version.substring(4)
const versionSeparator = aliasBase.lastIndexOf('@')
fullName = aliasBase.substring(0, versionSeparator)
name = fullName
version = aliasBase.substring(versionSeparator + 1)
}
let name = key;
let fullName = key;
let alias = '';
let version = packages[key];
if (version.startsWith('npm:')) {
alias = fullName;
const aliasBase = version.substring(4);
const versionSeparator = aliasBase.lastIndexOf('@');
fullName = aliasBase.substring(0, versionSeparator);
name = fullName;
version = aliasBase.substring(versionSeparator + 1);
}
let scope = undefined
if (name.indexOf('@') === 0) {
const scopeSeparator = name.indexOf('/')
scope = name.substring(1, scopeSeparator)
name = name.substring(scopeSeparator + 1, name.length)
}
let scope = undefined;
if (name.indexOf('@') === 0) {
const scopeSeparator = name.indexOf('/');
scope = name.substring(1, scopeSeparator);
name = name.substring(scopeSeparator + 1, name.length);
}
const newEntry = {
fullName: fullName,
alias: alias,
name: name,
version: version,
scope: scope
}
const newEntry = {
fullName: fullName,
alias: alias,
name: name,
version: version,
scope: scope,
};
const indexOfNewEntry = packageIndex.findIndex(entry => (entry.name === newEntry.name && entry.version === newEntry.version && entry.scope === newEntry.scope))
const indexOfNewEntry = packageIndex.findIndex(
(entry) =>
entry.name === newEntry.name &&
entry.version === newEntry.version &&
entry.scope === newEntry.scope,
);
if (indexOfNewEntry === -1) {
packageIndex.push(newEntry)
}
}
if (indexOfNewEntry === -1) {
packageIndex.push(newEntry);
}
}
}
export default addPackagesToIndex;

@@ -7,4 +7,4 @@ import path from 'node:path';

export default rc('license-report', {
/*
export const config = rc('license-report', {
/*
possible outputs:

@@ -14,31 +14,31 @@

*/
output: 'json',
output: 'json',
/*
/*
if output is html
*/
html: {
cssFile: path.resolve(__dirname, '..', 'defaultHtmlStyle.css'),
html: {
cssFile: path.resolve(__dirname, '..', 'defaultHtmlStyle.css'),
// passed directly to tableify (see: https://github.com/kessler/node-tableify)
tableify: {}
},
// passed directly to tableify (see: https://github.com/kessler/node-tableify)
tableify: {},
},
/*
/*
if output is csv
*/
delimiter: ',',
delimiter: ',',
/**
* if output is a markdown table.
* See https://github.com/haltcase/tablemark for details.
*/
tablemarkOptions: {},
/**
* if output is a markdown table.
* See https://github.com/haltcase/tablemark for details.
*/
tablemarkOptions: {},
/*
/*
escape fields containing delimiter character if output is csv
*/
escapeCsvFields: false,
escapeCsvFields: false,
/*
/*
export deps or dev deps. falsy -> output everything

@@ -48,108 +48,108 @@ possible values (as csv without whitespace):

*/
only: null,
only: null,
/*
/*
npm registry url
*/
registry: 'https://registry.npmjs.org/',
registry: 'https://registry.npmjs.org/',
/*
/*
name of the environment variable holding the access token for private npm registries
*/
npmTokenEnvVar: 'NPM_TOKEN',
npmTokenEnvVar: 'NPM_TOKEN',
/*
/*
an array of package names that will be excluded from the report
*/
exclude: [],
exclude: [],
/*
/*
a regular expression of package names that will be excluded from the report;
the regex string must not start or end with a forward slash (e.g. '^@bepo65\/.*')
*/
excludeRegex: '',
excludeRegex: '',
/*
/*
fields participating in the report and their order
*/
fields: [
'department',
'relatedTo',
'name',
'licensePeriod',
'material',
'licenseType',
'link',
'remoteVersion',
'installedVersion',
'definedVersion',
'author'
],
fields: [
'department',
'relatedTo',
'name',
'licensePeriod',
'material',
'licenseType',
'link',
'remoteVersion',
'installedVersion',
'definedVersion',
'author',
],
department: {
value: 'kessler',
label: 'department'
},
relatedTo: {
value: 'stuff',
label: 'related to'
},
licensePeriod: {
value: 'perpetual',
label: 'license period'
},
material: {
value: 'material',
label: 'material / not material'
},
name: {
value: '',
label: 'name'
},
licenseType: {
value: 'n/a',
label: 'license type'
},
link: {
value: 'n/a',
label: 'link'
},
installedFrom: {
value: 'n/a',
label: 'installed from'
},
remoteVersion: {
value: '',
label: 'remote version'
},
installedVersion: {
value: 'n/a',
label: 'installed version'
},
definedVersion: {
value: 'n/a',
label: 'defined version'
},
latestRemoteVersion: {
value: 'n/a',
label: 'latest remote version'
},
latestRemoteModified: {
value: 'n/a',
label: 'latest remote modified'
},
author: {
value: 'n/a',
label: 'author'
},
comment: {
value: '',
label: 'comment'
},
httpRetryOptions: {
limit: 5
},
httpTimeoutOptions: {
request: 30000
}
})
department: {
value: 'kessler',
label: 'department',
},
relatedTo: {
value: 'stuff',
label: 'related to',
},
licensePeriod: {
value: 'perpetual',
label: 'license period',
},
material: {
value: 'material',
label: 'material / not material',
},
name: {
value: '',
label: 'name',
},
licenseType: {
value: 'n/a',
label: 'license type',
},
link: {
value: 'n/a',
label: 'link',
},
installedFrom: {
value: 'n/a',
label: 'installed from',
},
remoteVersion: {
value: '',
label: 'remote version',
},
installedVersion: {
value: 'n/a',
label: 'installed version',
},
definedVersion: {
value: 'n/a',
label: 'defined version',
},
latestRemoteVersion: {
value: 'n/a',
label: 'latest remote version',
},
latestRemoteModified: {
value: 'n/a',
label: 'latest remote modified',
},
author: {
value: 'n/a',
label: 'author',
},
comment: {
value: '',
label: 'comment',
},
httpRetryOptions: {
limit: 5,
},
httpTimeoutOptions: {
request: 30000,
},
});

@@ -6,32 +6,41 @@ /**

*/
function extractAuthor(packageJSONContent) {
let author = 'n/a'
if (isObject(packageJSONContent.author)) {
author = packageJSONContent.author.name || ''
if (packageJSONContent.author.email) {
if (author.length > 0) {
author += ' ';
}
author += packageJSONContent.author.email;
}
export function extractAuthor(packageJSONContent) {
let author = 'n/a';
if (isObject(packageJSONContent.author)) {
author = packageJSONContent.author.name || '';
if (packageJSONContent.author.email) {
if (author.length > 0) {
author += ' ';
}
author += packageJSONContent.author.email;
}
if (packageJSONContent.author.url) {
if (author.length > 0){
author += ' ';
}
author += packageJSONContent.author.url;
}
} else {
if ((typeof packageJSONContent.author === 'string') || (packageJSONContent.author instanceof String)) {
author = packageJSONContent.author;
}
}
if (packageJSONContent.author.url) {
if (author.length > 0) {
author += ' ';
}
author += packageJSONContent.author.url;
}
} else {
if (
typeof packageJSONContent.author === 'string' ||
packageJSONContent.author instanceof String
) {
author = packageJSONContent.author;
}
}
return author
return author;
}
/**
* Is the given element an object?
* @param {*} element - element under inspection
* @returns {boolean} true if element is an object (or function)
*/
function isObject(element) {
return ((element !== null) && ((typeof element === "object") || (typeof element === 'function')))
return (
element !== null &&
(typeof element === 'object' || typeof element === 'function')
);
}
export default extractAuthor;

@@ -6,8 +6,8 @@ /**

*/
function extractInstalledFrom(json) {
if (json.dist && json.dist.tarball) {
return json.dist.tarball
}
export function extractInstalledFrom(json) {
if (json.dist && json.dist.tarball) {
return json.dist.tarball;
}
return;
}
export default extractInstalledFrom;

@@ -6,35 +6,32 @@ /**

*/
function extractLicense(packageJSONContent) {
const notAvailableText = 'n/a'
export function extractLicense(packageJSONContent) {
const notAvailableText = 'n/a';
if (typeof packageJSONContent.license === 'string') {
return packageJSONContent.license
}
if (typeof packageJSONContent.license === 'string') {
return packageJSONContent.license;
}
if (typeof packageJSONContent.license === 'object') {
return packageJSONContent.license.type
}
if (typeof packageJSONContent.license === 'object') {
return packageJSONContent.license.type;
}
let licenseType
if (Array.isArray(packageJSONContent.licenses)) {
licenseType = ''
for (let i = 0; i < packageJSONContent.licenses.length; i++) {
if (i > 0)
licenseType += ', '
let licenseType;
if (Array.isArray(packageJSONContent.licenses)) {
licenseType = '';
for (let i = 0; i < packageJSONContent.licenses.length; i++) {
if (i > 0) licenseType += ', ';
if (typeof packageJSONContent.licenses[i] === 'string') {
licenseType += packageJSONContent.licenses[i]
} else {
licenseType += packageJSONContent.licenses[i].type
}
}
if (licenseType.length === 0) {
licenseType = notAvailableText
}
} else {
licenseType = notAvailableText
}
return licenseType
if (typeof packageJSONContent.licenses[i] === 'string') {
licenseType += packageJSONContent.licenses[i];
} else {
licenseType += packageJSONContent.licenses[i].type;
}
}
if (licenseType.length === 0) {
licenseType = notAvailableText;
}
} else {
licenseType = notAvailableText;
}
return licenseType;
}
export default extractLicense;

@@ -8,28 +8,28 @@ import visit from 'visit-values';

*/
function extractLink(json) {
if (json.repository && json.repository.url) {
return json.repository.url
}
export function extractLink(json) {
if (json.repository && json.repository.url) {
return json.repository.url;
}
/*
/*
a feeble attempt to find some other url
*/
let otherUrls = []
let otherUrls = [];
visit(json, function(value) {
if (typeof value !== 'string') return
if (value.substr(0, 'http'.length) === 'http') {
return otherUrls.push(value)
}
visit(json, function (value) {
if (typeof value !== 'string') return;
if (value.substr(0, 'http'.length) === 'http') {
return otherUrls.push(value);
}
if (value.substr(0, 'git'.length) === 'git') {
return otherUrls.push(value)
}
})
if (value.substr(0, 'git'.length) === 'git') {
return otherUrls.push(value);
}
});
if (otherUrls.length > 0) {
return otherUrls[0]
}
if (otherUrls.length > 0) {
return otherUrls[0];
}
return;
}
export default extractLink;

@@ -1,3 +0,3 @@

import addPackagesToIndex from './addPackagesToIndex.js';
import util from './util.js';
import { addPackagesToIndex } from './addPackagesToIndex.js';
import { isNullOrUndefined } from './util.js';

@@ -14,26 +14,64 @@ /**

* @param {string[]} exclusionRegex - RegExp object created from config.excludeRegex defining additional excluded packages
* @return {object[]} with dependencies
* @returns {object[]} with dependencies
*/
function getDependencies(packageJson, exclusions, inclusions, exclusionRegex) {
let depsIndex = []
const noDepsTypeDefined = util.isNullOrUndefined(inclusions) || !Array.isArray(inclusions) || (inclusions.length === 0)
if ((noDepsTypeDefined || (inclusions.indexOf('prod') > -1)) && (packageJson.dependencies !== undefined)) {
addPackagesToIndex(packageJson.dependencies, depsIndex, exclusions, exclusionRegex);
export function getDependencies(
packageJson,
exclusions,
inclusions,
exclusionRegex,
) {
let depsIndex = [];
const noDepsTypeDefined =
isNullOrUndefined(inclusions) ||
!Array.isArray(inclusions) ||
inclusions.length === 0;
if (
(noDepsTypeDefined || inclusions.indexOf('prod') > -1) &&
packageJson.dependencies !== undefined
) {
addPackagesToIndex(
packageJson.dependencies,
depsIndex,
exclusions,
exclusionRegex,
);
}
if ((noDepsTypeDefined || (inclusions.indexOf('dev') > -1)) && (packageJson.devDependencies !== undefined)) {
addPackagesToIndex(packageJson.devDependencies, depsIndex, exclusions, exclusionRegex);
if (
(noDepsTypeDefined || inclusions.indexOf('dev') > -1) &&
packageJson.devDependencies !== undefined
) {
addPackagesToIndex(
packageJson.devDependencies,
depsIndex,
exclusions,
exclusionRegex,
);
}
if ((noDepsTypeDefined || (inclusions.indexOf('peer') > -1)) && (packageJson.peerDependencies !== undefined)) {
addPackagesToIndex(packageJson.peerDependencies, depsIndex, exclusions, exclusionRegex);
if (
(noDepsTypeDefined || inclusions.indexOf('peer') > -1) &&
packageJson.peerDependencies !== undefined
) {
addPackagesToIndex(
packageJson.peerDependencies,
depsIndex,
exclusions,
exclusionRegex,
);
}
if ((noDepsTypeDefined || (inclusions.indexOf('opt') > -1)) && (packageJson.optionalDependencies !== undefined)) {
addPackagesToIndex(packageJson.optionalDependencies, depsIndex, exclusions, exclusionRegex);
if (
(noDepsTypeDefined || inclusions.indexOf('opt') > -1) &&
packageJson.optionalDependencies !== undefined
) {
addPackagesToIndex(
packageJson.optionalDependencies,
depsIndex,
exclusions,
exclusionRegex,
);
}
return depsIndex
return depsIndex;
}
export default getDependencies;

@@ -5,11 +5,13 @@ import fs from 'node:fs';

import tablemark from 'tablemark';
import { isNullOrUndefined, nestedPropertyValue } from './util.js';
/**
* Formats package information as json string.
* @param dataAsArray - array of objects with information about dependencies / devdependencies in package.json
* @param config - global configuration object
* @returns dataAsArray formatted as json string
* @param {object[]} dataAsArray - array of objects with information about dependencies / devDependencies in package.json
* @param {object} config - global configuration object
* @returns {string} dataAsArray formatted as json string
*/
// eslint-disable-next-line no-unused-vars
function formatAsJsonString(dataAsArray, config) {
return JSON.stringify(dataAsArray)
return JSON.stringify(dataAsArray);
}

@@ -19,24 +21,31 @@

* Formats package information as table.
* @param dataAsArray - array of objects with information about dependencies / devdependencies in package.json
* @param config - global configuration object
* @returns dataAsArray formatted as table string
* @param {object[]} dataAsArray - array of objects with information about dependencies / devDependencies in package.json
* @param {object} config - global configuration object
* @returns {string} dataAsArray formatted as table string
*/
function formatAsTable(dataAsArray, config) {
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let data = arrayOfObjectsToArrayOfArrays(dataAsArray)
let labels = []
let lines = []
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let data = arrayOfObjectsToArrayOfArrays(dataAsArray);
let labels = [];
let lines = [];
// create a labels array and a lines array
// the lines will be the same length as the label's
for (let i = 0; i < fieldsList.length; i++) {
let label = config[fieldsList[i]].label
labels.push(label)
lines.push('-'.repeat(label.length))
}
// create a labels array and a lines array
// the lines will be the same length as the label's
for (let i = 0; i < fieldsList.length; i++) {
let label = fieldsList[i];
const fieldDefinition = nestedPropertyValue(config, fieldsList[i]);
if (fieldDefinition?.label !== undefined) {
label = fieldDefinition.label;
}
data.unshift(lines)
data.unshift(labels)
labels.push(label);
lines.push('-'.repeat(label.length));
}
return table(data)
data.unshift(lines);
data.unshift(labels);
return table(data);
}

@@ -47,38 +56,42 @@

* The names of the properties are used as column headers (if config.csvHeaders is true).
* @param dataAsArray - array of objects with information about dependencies / devdependencies in package.json
* @param config - global configuration object
* @returns dataAsArray formatted as csv string
* @param {object[]} dataAsArray - array of objects with information about dependencies / devDependencies in package.json
* @param {object} config - global configuration object
* @returns {string} dataAsArray formatted as csv string
*/
function formatAsCsv(dataAsArray, config) {
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let data = arrayOfObjectsToArrayOfArrays(dataAsArray)
let csv = []
const delimiter = config.delimiter
const escapeFields = config.escapeCsvFields
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let data = arrayOfObjectsToArrayOfArrays(dataAsArray);
let csv = [];
const delimiter = config.delimiter;
const escapeFields = config.escapeCsvFields;
if (config.csvHeaders) {
let labels = []
// create a labels array and a lines array
for (let i = 0; i < fieldsList.length; i++) {
labels.push(config[fieldsList[i]].label)
}
csv.push(labels.join(delimiter))
}
if (config.csvHeaders) {
let labels = [];
// create a labels array and a lines array
for (let i = 0; i < fieldsList.length; i++) {
labels.push(config[fieldsList[i]].label);
}
csv.push(labels.join(delimiter));
}
for (const element of data) {
const validatedFields = element.map(fieldValue => {
let validatedField = fieldValue
if (fieldValue.includes(delimiter)) {
console.warn(`Warning: field contains delimiter; value: "${fieldValue}"`)
if (escapeFields) {
validatedField = `"${fieldValue}"`
}
}
return validatedField
})
for (const element of data) {
const validatedFields = element.map((fieldValue) => {
let validatedField = fieldValue;
if (fieldValue.includes(delimiter)) {
console.warn(
`Warning: field contains delimiter; value: "${fieldValue}"`,
);
if (escapeFields) {
validatedField = `"${fieldValue}"`;
}
}
return validatedField;
});
csv.push(validatedFields.join(delimiter))
}
csv.push(validatedFields.join(delimiter));
}
return csv.join('\n')
return csv.join('\n');
}

@@ -89,15 +102,21 @@

* To use the labels of the properties set in config as headers, the properties are renamed.
* @param dataAsArray - array of objects with information about dependencies / devdependencies in package.json
* @param config - global configuration object
* @returns dataAsArray formatted as html
* @param {object[]} dataAsArray - array of objects with information about dependencies / devDependencies in package.json
* @param {object} config - global configuration object
* @returns {string} dataAsArray formatted as html
*/
function formatAsHTML(dataAsArray, config) {
let rowsToBeDisplayed
if (dataAsArray.length > 0) {
rowsToBeDisplayed = dataAsArray.map(row => renameRowsProperties(row, config))
} else {
rowsToBeDisplayed = [ dataArrayWithEmptyRow(config) ]
}
let rowsToBeDisplayed;
if (dataAsArray.length > 0) {
rowsToBeDisplayed = dataAsArray.map((row) =>
renameRowsProperties(row, config),
);
} else {
rowsToBeDisplayed = [dataArrayWithEmptyRow(config)];
}
return tableify.htmlDoc(rowsToBeDisplayed, config.html.tableify, fs.readFileSync(config.html.cssFile))
return tableify.htmlDoc(
rowsToBeDisplayed,
config.html.tableify,
fs.readFileSync(config.html.cssFile),
);
}

@@ -107,17 +126,19 @@

* Formats package information as a markdown table. The names of the properties are used as column headers.
* @param dataAsArray - array of objects with information about dependencies / devdependencies in package.json
* @param config - global configuration object
* @returns dataAsArray formatted as a markdown table
* @param {object[]} dataAsArray - array of objects with information about dependencies / devDependencies in package.json
* @param {object} config - global configuration object
* @returns {string} dataAsArray formatted as a markdown table
*/
function formatAsMarkdown(dataAsArray, config) {
let result = ''
if (dataAsArray.length > 0) {
// Respect the possibly overridden field names
const dataAsArrayWithRenamedFields = dataAsArray.map(row => renameRowsProperties(row, config))
result = tablemark(dataAsArrayWithRenamedFields, config.tablemarkOptions)
}
return result
let result = '';
if (dataAsArray.length > 0) {
// Respect the possibly overridden field names
const dataAsArrayWithRenamedFields = dataAsArray.map((row) =>
renameRowsProperties(row, config),
);
result = tablemark(dataAsArrayWithRenamedFields, config.tablemarkOptions);
}
return result;
}
/**

@@ -127,44 +148,47 @@ * Gets the formatter function for the style given.

* Function signature: function(dataAsArray, config)
* dataAsArray: array of objects with information about dependencies / devdependencies in package.json,
* dataAsArray: array of objects with information about dependencies / devDependencies in package.json,
* config: global configuration object
* @param style - output style to be generated
* @returns function to format the data; signature: function(dataAsArray, config)
* @param {string} style - output style to be generated
* @returns {Function} function to format the data; signature: function(dataAsArray, config)
*/
function getFormatter(style) {
let formatter
switch (style) {
case 'json':
formatter = formatAsJsonString
break
case 'table':
formatter = formatAsTable
break
case 'csv':
formatter = formatAsCsv
break
case 'html':
formatter = formatAsHTML
break
case 'markdown':
formatter = formatAsMarkdown
break
default:
throw new Error('invalid output format in config')
}
export function getFormatter(style) {
let formatter;
switch (style) {
case 'json':
formatter = formatAsJsonString;
break;
case 'table':
formatter = formatAsTable;
break;
case 'csv':
formatter = formatAsCsv;
break;
case 'html':
formatter = formatAsHTML;
break;
case 'markdown':
formatter = formatAsMarkdown;
break;
default:
throw new Error('invalid output format in config');
}
return formatter
return formatter;
}
/**
* Convert an array of objects to an array of arrays
* @param {object[]} arrayOfObjects - array of objects to be converted
* @returns {string[][]} converted array
*/
function arrayOfObjectsToArrayOfArrays(arrayOfObjects) {
const arrayOfArrays = arrayOfObjects.map(objectElement => {
let objectAsArray = Object.values(objectElement)
return objectAsArray.map(arrayElement => !isNullOrUndefined(arrayElement) ? arrayElement : 'n/a')
})
return arrayOfArrays
const arrayOfArrays = arrayOfObjects.map((objectElement) => {
let objectAsArray = Object.values(objectElement);
return objectAsArray.map((arrayElement) =>
!isNullOrUndefined(arrayElement) ? arrayElement : 'n/a',
);
});
return arrayOfArrays;
}
function isNullOrUndefined(value) {
return ((value === undefined) || (value === null))
}
/**

@@ -174,8 +198,8 @@ * Rename the property of an object

* @param {string} newProp - new name of the property
* @param {object} anonymous - object with the property to be renamed
* @param {string} old - value of the old property
* @returns {object} object with the renamed property
*/
function renameProp(oldProp, newProp, { [oldProp]: old, ...others }) {
const newObject = {[newProp]:old, ...others}
return newObject
const newObject = { [newProp]: old, ...others };
return newObject;
}

@@ -187,11 +211,20 @@

* @param {object} config - configuration object
* @returns {object} row with renamed properties
*/
function renameRowsProperties(row, config) {
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let renamedRow = row
for (let i = fieldsList.length - 1; i >= 0; i--) {
const fieldname = fieldsList[i];
renamedRow = renameProp(fieldname, config[fieldname].label, renamedRow)
}
return renamedRow
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let renamedRow = row;
for (let i = fieldsList.length - 1; i >= 0; i--) {
const fieldname = fieldsList[i];
let newFieldname = fieldname;
const fieldDefinition = nestedPropertyValue(config, fieldname);
if (fieldDefinition?.label !== undefined) {
newFieldname = fieldDefinition.label;
}
renamedRow = renameProp(fieldname, newFieldname, renamedRow);
}
return renamedRow;
}

@@ -208,12 +241,12 @@

function dataArrayWithEmptyRow(config) {
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let emptyRow = {}
// create an array with 1 line of empty entries, to display empty table with header
for (let i = fieldsList.length - 1; i >= 0; i--) {
let label = config[fieldsList[i]].label
emptyRow[label] = ' '
}
return emptyRow
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let emptyRow = {};
// create an array with 1 line of empty entries, to display empty table with header
for (let i = fieldsList.length - 1; i >= 0; i--) {
let label = config[fieldsList[i]].label;
emptyRow[label] = ' ';
}
return emptyRow;
}
export default getFormatter;

@@ -6,5 +6,7 @@ import path from 'node:path';

import config from './config.js';
import { config } from './config.js';
const debug = createDebugMessages('license-report:getPackageDataFromRepository');
const debug = createDebugMessages(
'license-report:getPackageDataFromRepository',
);

@@ -14,45 +16,54 @@ /**

* @param {string} name - full name of the package
* @returns {object} with all informations about a package
* @returns {object} with all information about a package
*/
async function getPackageDataFromRepository(name) {
const uri = path.join(config.registry, name)
export async function getPackageDataFromRepository(name) {
const uri = path.join(config.registry, name);
debug('getPackageDataFromRepository - REQUEST %s', uri)
debug('getPackageDataFromRepository - REQUEST %s', uri);
const options = {
retry: config.httpRetryOptions,
timeout: config.httpTimeoutOptions,
hooks: {
beforeRetry: [
(error, retryCount) => {
debug(`http request to npm for package "${name}" failed, retrying again soon...`)
}
],
beforeError: [
error => {
debug(error)
return error
}
]
}
}
const options = {
retry: config.httpRetryOptions,
timeout: config.httpTimeoutOptions,
hooks: {
beforeRetry: [
// eslint-disable-next-line no-unused-vars
(error, retryCount) => {
debug(
`http request to npm for package "${name}" failed, retrying again soon...`,
);
},
],
beforeError: [
(error) => {
debug(error);
return error;
},
],
},
};
if ((config.npmTokenEnvVar !== null) && (config.npmTokenEnvVar !== undefined) && (config[config.npmTokenEnvVar] !== undefined)) {
console.warn(`the environment variable '${config.npmTokenEnvVar}' containing the token used by npm to access the private repository should not be a configuration parameter (this is a severe security problem!)`)
}
const npmToken = process.env[config.npmTokenEnvVar] || ''
if (npmToken.trim().length > 0) {
options['headers'] = { 'Authorization': `Bearer ${npmToken}` }
}
if (
config.npmTokenEnvVar !== null &&
config.npmTokenEnvVar !== undefined &&
config[config.npmTokenEnvVar] !== undefined
) {
console.warn(
`the environment variable '${config.npmTokenEnvVar}' containing the token used by npm to access the private repository should not be a configuration parameter (this is a severe security problem!)`,
);
}
const npmToken = process.env[config.npmTokenEnvVar] || '';
if (npmToken.trim().length > 0) {
options['headers'] = { Authorization: `Bearer ${npmToken}` };
}
let response = {}
try {
response = await got(uri, options).json()
} catch (error) {
debug(`http request to npm for package "${name}" failed with error '${error}'`)
}
let response = {};
try {
response = await got(uri, options).json();
} catch (error) {
debug(
`http request to npm for package "${name}" failed with error '${error}'`,
);
}
return response
return response;
}
export default getPackageDataFromRepository;

@@ -0,1 +1,3 @@

import { nestedPropertyValue } from './util.js';
/**

@@ -6,22 +8,28 @@ * Create object with all fields listed in config.fields with current values about one package.

* entry in the config file (e.g. from config.material.value for the 'material' field).
* @param packageData - object with information about one package (fields are e.g. 'name', 'licenseType', 'link', 'remoteVersion', 'installedVersion', 'author')
* @param config - global configuration object
* @returns object with all fields listed in config.fields
* @param {object} packageData - object with information about one package (fields are e.g. 'name', 'licenseType', 'link', 'remoteVersion', 'installedVersion', 'author')
* @param {object} config - global configuration object
* @returns {object} object with all fields listed in config.fields
*/
function packageDataToReportData(packageData, config) {
const fieldsList = Array.isArray(config.fields) ? config.fields : [config.fields]
let finalData = {}
export function packageDataToReportData(packageData, config) {
const fieldsList = Array.isArray(config.fields)
? config.fields
: [config.fields];
let finalData = {};
// create only fields specified in the config
fieldsList.forEach(fieldName => {
if ((fieldName in packageData)) {
finalData[fieldName] = packageData[fieldName]
} else {
finalData[fieldName] = config[fieldName].value
}
})
// create only fields specified in the config
fieldsList.forEach((fieldName) => {
if (fieldName in packageData) {
finalData[fieldName] = packageData[fieldName];
} else {
let value = 'n/a';
const fieldDefinition = nestedPropertyValue(config, fieldName);
if (fieldDefinition?.value !== undefined) {
value = fieldDefinition.value;
}
return finalData
finalData[fieldName] = value;
}
});
return finalData;
}
export default packageDataToReportData;

@@ -8,13 +8,42 @@ import fs from 'node:fs';

*/
async function readJson(path) {
const data = await fs.promises.readFile(path)
return JSON.parse(data)
export async function readJson(path) {
const data = await fs.promises.readFile(path);
return JSON.parse(data);
}
function isNullOrUndefined(element) {
return ((element === undefined) || (element === null))
/**
* Is element null or undefined?
* @param {*} element - element under inspection
* @returns {boolean} true if element is null or undefined
*/
export function isNullOrUndefined(element) {
return element === undefined || element === null;
}
const helpText = `Generate a detailed report of the licenses of all projects dependencies.
/**
* Get a nested object property by pathname (a dotted string).
* Examples:
* getNestedPropertyFromKeyString(data, ['foo.bar']); // returns value of 'data.foo.bar'.
* getNestedPropertyFromKeyString(data, ['foo.bar[2].baz']); // returns value of 'data.foo.bar[2].baz',
* if data.foo.bar is an array with at least 3 elements.
* @param {object} obj - object containing the requested property
* @param {string} keyPath - key used to address the property (e.g.'foo.bar.baz')
* @returns {any} value of the requested property or undefined
*/
export function nestedPropertyValue(obj, keyPath) {
let result = undefined;
if (!keyPath.includes('.')) {
result = obj[keyPath];
} else {
const keys = keyPath
.replace(/\[([^[\]]*)\]/g, '.$1.') // change array index to dot separators
.split('.')
.filter(t => t !== ''); // remove empty entries
result = keys.reduce((prevValue, currKey) => prevValue?.[currKey] ?? undefined, obj);
}
return result;
}
export const helpText = `Generate a detailed report of the licenses of all projects dependencies.
Usage: license-report [options]

@@ -46,8 +75,2 @@

department, relatedTo, licensePeriod, material.
`
export default {
readJson,
isNullOrUndefined,
helpText
};
`;
{
"name": "license-report",
"version": "6.5.0",
"version": "6.7.0",
"description": "creates a short report about project's dependencies (license, url etc)",
"main": "index.js",
"scripts": {
"lint": "npx eslint index.js lib/**/*.js test/**/*.js **/*.json",
"test": "npx mocha -R spec",
"release": "standard-version --commit-all",
"lint-commits": "commitlint --from 59f5e4b90d2d --to HEAD --verbose",
"activate-commitlint": "npx husky install && npx husky add .husky/commit-msg \"npx --no -- commitlint --edit $1\""
"release": "commit-and-tag-version -i CHANGELOG.md --same-file",
"lint-commits": "commitlint --from 59f5e4b90d2d --to HEAD --verbose"
},
"bin": {
"license-report": "index.js"
"license-report": "./index.js"
},

@@ -18,3 +18,3 @@ "type": "module",

"type": "git",
"url": "https://github.com/ironSource/license-report"
"url": "https://github.com/kessler/license-report"
},

@@ -24,13 +24,13 @@ "author": "Yaniv Kessler",

"bugs": {
"url": "https://github.com/ironSource/license-report/issues"
"url": "https://github.com/kessler/license-report/issues"
},
"homepage": "https://github.com/ironSource/license-report",
"homepage": "https://github.com/kessler/license-report",
"dependencies": {
"@kessler/tableify": "^1.0.2",
"debug": "^4.3.4",
"eol": "^0.9.1",
"got": "^13.0.0",
"debug": "^4.3.6",
"eol": "^0.10.0",
"got": "^14.4.2",
"rc": "^1.2.8",
"semver": "^7.5.4",
"tablemark": "^3.0.0",
"semver": "^7.6.3",
"tablemark": "^3.1.0",
"text-table": "^0.2.0",

@@ -40,11 +40,21 @@ "visit-values": "^2.0.0"

"devDependencies": {
"@commitlint/cli": "^17.7.2",
"@commitlint/config-conventional": "^17.7.0",
"husky": "^8.0.3",
"mocha": "^10.2.0",
"nock": "^13.3.3",
"standard-version": "^9.5.0"
"@commitlint/cli": "^19.4.1",
"@commitlint/config-conventional": "^19.4.1",
"commit-and-tag-version": "^12.4.2",
"eslint": "^9.9.1",
"eslint-plugin-chai-expect": "^3.1.0",
"eslint-plugin-jsdoc": "^50.2.2",
"eslint-plugin-json": "^4.0.1",
"eslint-plugin-mocha": "^10.5.0",
"eslint-plugin-n": "^17.10.2",
"eslint-plugin-security": "^3.0.1",
"eslint-plugin-security-node": "^1.1.4",
"husky": "^9.1.5",
"lint-staged": "^15.2.9",
"mocha": "^10.7.3",
"nock": "^13.5.5",
"prettier": "^3.3.3"
},
"engines": {
"node": ">=16"
"node": ">=18"
},

@@ -60,3 +70,33 @@ "files": [

"screenshot.png"
]
],
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"commit-and-tag-version": {
"packageFiles": [
{
"filename": "package.json",
"type": "json"
}
],
"bumpFiles": [
{
"filename": "package.json",
"type": "json"
},
{
"filename": "package-lock.json",
"type": "json"
},
{
"filename": "README.md",
"updater": "scripts/readme-updater.cjs"
}
]
}
}

@@ -0,3 +1,10 @@

# ANNOUNCEMENT: repository changing ownership
On the 16th of March 2024 this repository will change ownership and move to the personal account of one of it's maintainers, [Yaniv Kessler](https://github.com/kessler)
Ownership change will also occur on the npm registry to [Yaniv Kessler](https://www.npmjs.com/~kessler)
# NPM License Report Tool
![Version](https://img.shields.io/badge/version-6.5.0-blue.svg?cacheSeconds=2592000)
![Version](https://img.shields.io/badge/version-6.7.0-blue.svg?cacheSeconds=2592000)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/kefranabg/readme-md-generator/blob/master/LICENSE)

@@ -8,9 +15,13 @@

## Installation
```
npm install -g license-report
```
## Functionality
`license-report` gets the dependencies of a program or package from its `package.json` file and for each dependency adds the installed version, the license type and the author from the corresponding `package.json` file in the `node_modules` directory and the latest available version and other data from the (npm) registry where this package was installed from.
`license-report` gets the dependencies of a program or package from its `package.json` file and for each dependency adds the installed version, the license type and the author from the corresponding `package.json` file in the `node_modules` directory and the latest available version and other data from the (npm) registry where this package was installed from.
## Prerequisites
1. The dependencies of the project under inspection must be installed so that the node_modules directory exists in the path of the `package.json` file.

@@ -22,3 +33,5 @@ 2. The registry defined in the `registry` configuration setting must be accessible (default: 'https://registry.npmjs.org/').

### Run license-report without options:
By default, `license-report` outputs all licenses from `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`.
```

@@ -32,11 +45,15 @@ cd your/project/

To specify one or some dependency types, use configuration options, e.g.
```
license-report --only=dev
```
```
license-report --only=prod
```
```
license-report --only=prod,opt,peer
```
The 'only' option is a comma separated list of the dependencies to use.

@@ -52,3 +69,5 @@ Possible values are:

### Explicit package.json:
To define the package.json to inspect, use the 'package' option.
```

@@ -59,3 +78,5 @@ license-report --package=/path/to/package.json

### Customize a field's label:
The configurable labels are used as column headers in table / csv / html output. For html output the labels of all fields in the output must be unique.
```

@@ -66,3 +87,5 @@ license-report --department.label=division

### Customize a fields default value:
Only applicable for the fields in the list later in this document and for "custom" fields (look for "Fields with data set in the configuration of license-report")
```

@@ -73,3 +96,5 @@ license-report --department.value=ninjaSquad

### Use another registry:
To define the registry, the remote data for packages are fetched from, use the 'registry' option.
```

@@ -80,3 +105,5 @@ license-report --registry=https://myregistry.com/

### Registry with authorization:
To use a npm registry that requires authorization, the option `npmTokenEnvVar` must contain the name of an environment variable that contains the required npm authorization token (the default name is 'NPM_TOKEN'). An example:
```

@@ -86,5 +113,7 @@ # if the name of the environment variable containing the bearer token for npm authorization is 'NPM_TOKEN'

```
The name of this environment variable (in the example: 'npm_token') should not be added as an option to the license-report config file, as this implies a severe security risk, when this file is checked in into a git repository. A warning is emitted if such an option is found in the config file.
### Generate different outputs:
```

@@ -98,3 +127,3 @@ license-report --output=table

# replace default ',' separator with something else
license-report --output=csv --delimiter="|"
license-report --output=csv --delimiter="|"

@@ -110,5 +139,7 @@ # output csv headers (fields) on first row

```
When using the 'hcat' package to open the result in a browser, this package must be globally installed with `npm i -g hcat`.
### Select fields for output:
If only a few fields are required in the output, the easiest way of selecting the fields is via --fields command line arguments.

@@ -122,2 +153,3 @@

If more fields are needed, the best way is to use a custom config file, that contains a fields array.
```

@@ -127,2 +159,3 @@ # set options with command line option for custom (partial) config file

```
```

@@ -145,5 +178,13 @@ # example of config file for backward compatible output:

```
### Custom fields
Besides the 'build-in' fields ("department", "name", "installedVersion", "author" "comment", "licensePeriod", "licenseType", "link", "material", "relatedTo"), any field allowed in a package.json can be used in the fields array (as "custom" field).
When using "custom" field, an element named like the "custom" field with 2 properties must be added: "value" - the default value for this field - and "label - the "heading" for generated columns. Here is an example for adding the 'homepage' field:
When using a "custom" field, an element named like the "custom" field with 2 properties must be added: "value" - the default value for this field - and "label - the "heading" for generated columns.
When the selected field is an object (e.g. the repository field is often an object) the object will be in the json output. If the output is of type table (or any of the other text based formats) the result of the toString function is used (resulting in "[object Object]" as default).
Here is an example for adding the 'homepage' and the repository field:
```

@@ -153,3 +194,5 @@ "fields": [

"installedVersion",
"homepage"
"homepage",
"repository",
"repository.url",
],

@@ -159,7 +202,19 @@ "homepage": {

"label": 'Homepage'
}
},
"repository": {
"value": 'n/a',
"label": 'Repo'
},
"repository": {
"url": {
"value": 'n/a',
"label": 'RepoURL'
}
},
```
### Exclude packages:
With the 'exclude' option, single packages can be excluded from the output.
```

@@ -170,2 +225,3 @@ license-report --exclude=async --exclude=rc

Using the 'excludeRegex' option, packages can be excluded from the output using a regular expression.
```

@@ -178,5 +234,7 @@ license-report --excludeRegex=@mycompany\/.*

### Markdown Options
If you want to change the default markdown table look and feel, e.g. center-align the text, you have to use a custom config file (`--config=license-report-config.json`) and in the config file use the `tablemarkConfig` property.
If you want to change the default markdown table look and feel, e.g. center-align the text, you have to use a custom config file )`--config=license-report-config.json`) and in the config file use the `tablemarkConfig` property.
Example config for markdown table with center-aligned content:
```JSON

@@ -211,2 +269,3 @@ "output": "markdown",

```
For an explanation of all available options see https://github.com/haltcase/tablemark

@@ -221,2 +280,3 @@

## "Build-in" fields
Fields with data of the installed packages:

@@ -237,13 +297,14 @@ | fieldname | column title | data source |

&nbsp;
&nbsp;
Fields with data set in the configuration of license-report:
| fieldname | column title | set value |
|--|---|---|
| department | department | --department.value=kessler |
| relatedTo | related to | --relatedTo.value=stuff |
| licensePeriod | license period | --licensePeriod.value=perpetual |
| material | material / not material | --material.value=material |
| fieldname | column title | set value |
| ------------- | ----------------------- | ------------------------------- |
| department | department | --department.value=kessler |
| relatedTo | related to | --relatedTo.value=stuff |
| licensePeriod | license period | --licensePeriod.value=perpetual |
| material | material / not material | --material.value=material |
## More configuration options
See `lib/config.js` for more details e.g. on customizing the generated html data.

@@ -254,2 +315,3 @@

A default project configuration file must be placed in the project root path and be named `.license-reportrc`. The file format is 'json'. An example looks like this:
```

@@ -278,2 +340,3 @@ {

By setting the debug environment variable as follows, detailed log information is generated during the report generation. For details see the documentation of the debug package on npm.
```

@@ -284,5 +347,7 @@ export DEBUG=license-report*

## Changelog
For list of changes and bugfixes, see [CHANGELOG.md](CHANGELOG.md).
## Contributing
The [CHANGELOG.md](CHANGELOG.md) is generated with `standard-changelog` (using the command `npm run release`).

@@ -299,15 +364,16 @@

The following is the list of supported types:
* build: changes that affect build components like build tool, ci pipeline, dependencies, project version, etc...
* chore: changes that aren't user-facing (e.g. merging branches).
* docs: changes that affect the documentation.
* feat: changes that introduce a new feature.
* fix: changes that patch a bug.
* perf: changes which improve performance.
* refactor: changes which neither fix a bug nor add a feature.
* revert: changes that revert a previous commit.
* style: changes that don't affect code logic, such as white-spaces, formatting, missing semi-colons.
* test: changes that add missing tests or correct existing tests.
- build: changes that affect build components like build tool, ci pipeline, dependencies, project version, etc...
- chore: changes that aren't user-facing (e.g. merging branches).
- docs: changes that affect the documentation.
- feat: changes that introduce a new feature.
- fix: changes that patch a bug.
- perf: changes which improve performance.
- refactor: changes which neither fix a bug nor add a feature.
- revert: changes that revert a previous commit.
- style: changes that don't affect code logic, such as white-spaces, formatting, missing semi-colons.
- test: changes that add missing tests or correct existing tests.
To ensure the syntax of commit messages `commitlint` is used, triggered by `husky`. This feature must be activated with `npm run activate-commitlint` once for every local clone of `license-report`.
![ironSource logo](ironsource.png)

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc