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

license-report

Package Overview
Dependencies
Maintainers
2
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.3.0 to 6.4.0

test/fixture/all-fields/license-report-config-custom-fields.json

13

CHANGELOG.md

@@ -5,2 +5,15 @@ # Changelog

## [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))
### 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))
## [6.3.0](https://github.com/ironSource/license-report/compare/v6.2.0...v6.3.0) (2022-10-19)

@@ -7,0 +20,0 @@

8

index.js

@@ -45,3 +45,3 @@ #!/usr/bin/env node

// an index of all the dependencies
// Get a list of all the dependencies we want information about.
const inclusions = util.isNullOrUndefined(config.only) ? null : config.only.split(',')

@@ -54,5 +54,5 @@ const exclusions = Array.isArray(config.exclude) ? config.exclude : [config.exclude]

depsIndex.map(async (element) => {
const localDataForPackages = await addLocalPackageData(element, projectRootPath)
const packagesData = await addPackageDataFromRepository(localDataForPackages)
return packageDataToReportData(packagesData, config)
const localDataForPackage = await addLocalPackageData(element, projectRootPath, config.fields)
const completeDataForPackage = await addPackageDataFromRepository(localDataForPackage)
return packageDataToReportData(completeDataForPackage, config)
})

@@ -59,0 +59,0 @@ )

@@ -12,12 +12,16 @@ import fs from 'node:fs';

/**
* Extracts information about a package from the corresponding package.json file
* and adds it to the given 'element' object.
* Extract information about a package from the corresponding package.json file
* and add it to the given 'element' object.
* The fetched entries are 'installedVersion', 'author', 'licenseType' and the
* properties of the package.json defined in the 'fields' list.
* If package.json file is found, 'n/a' is added as installedVersion.
* The logic to resolve mimics nodes logic (if not found, step up 1 level up to root)
* @param {object} element - entry for a package in depsIndex
* @param {object} element - object entry of depsIndex defining a package (name, version etc.)
* @param {string} projectRootPath - path of the package.json the report is generated for
* @param fields - 'fields' list from the global configuration object
* @returns {object} element with installedVersion, author and licenseType added
*/
async function addLocalPackageData(element, projectRootPath) {
async function addLocalPackageData(element, projectRootPath, fields) {
const notAvailableText = 'n/a'
const exclusionList = ['installedVersion', 'author', 'licenseType']

@@ -31,2 +35,3 @@ let projectPackageJsonPath = projectRootPath

let packageFolderName

@@ -48,2 +53,10 @@ if (element.alias.length === 0) {

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]
}
})
break

@@ -50,0 +63,0 @@ }

@@ -16,4 +16,5 @@ import semver from 'semver';

/**
* Collects the data for a single package (link, installedFrom, remoteVersion)
* @param {object} packageEntry - object with information about 1 dependency from the package.json
* Collects the data for a single package from the repository (link, installedFrom, remoteVersion) and
* add it to the given object.
* @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

@@ -42,2 +43,3 @@ */

let lastModified = ''
const fullPackageName = packageEntry.fullName

@@ -107,17 +109,19 @@

return {
name: fullPackageName,
author: author,
licenseType: licenseType,
link: link,
installedFrom: installedFrom,
definedVersion: definedVersion,
installedVersion: installedVersion,
remoteVersion: version.toString(),
latestRemoteVersion: latest,
latestRemoteModified: lastModified,
comment: version.toString()
}
// 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;
/**
* Add all packages to a package index array maintaining uniqueness (crudely)
* @param {object} packages - element from package.json (e.g. 'dependencies' or 'devDependencies')
* @param {[object]} packageIndex - array containing the entries for packages ('package index')
* @param {[object]} exclusions - exclusions list from config
* Add information about all packages from one of the dependencies (e.g. 'devDependencies') to
* an array ('packageIndex'), while maintaining uniqueness (crudely).
* For each package the following information is added: 'name', 'fullName', 'alias', 'version', 'scope'
* @param {object} packages - object with dependencies from a package.json (e.g. value of 'dependencies' or 'devDependencies')
* @param {object[]} packageIndex - array, the information about the packages are added to ('package index') - input/output value!
* @param {object[]} exclusions - exclusions list from config
*/

@@ -7,0 +9,0 @@ function addPackagesToIndex(packages, packageIndex, exclusions) {

@@ -5,7 +5,9 @@ import addPackagesToIndex from './addPackagesToIndex.js';

/**
* Get dependencies from given package.json file that follow the definition in depsType.
* 'inclusions' is equivalent to the 'only' parameter in the config definition, split into an array of strings.
* Get dependencies from given package.json file that follow the definition in 'inclusions' and 'exclusions'.
* For each package the following information is added: 'name', 'fullName', 'alias', 'version', 'scope'
* 'inclusions' is equivalent to the 'only' parameter in the config file, split into an array of strings.
* Complete list: ['prod', 'dev', 'opt', 'peer'] or null or undefined.
* 'exclusions' is equivalent to the 'exclude' parameter in the config file.
* @param {object} packageJson - content of package.json
* @param {string[]} exclusions - array of package names to be excluded
* @param {string[]} exclusions - array of package names to be excluded (from config.exclude)
* @param {string[]} inclusions - array of strings of types of dependencies to be included (from config.only)

@@ -12,0 +14,0 @@ * @return {object[]} with dependencies

@@ -106,6 +106,10 @@ import fs from 'node:fs';

function formatAsMarkdown(dataAsArray, config) {
// Respect the possibly overridden field names
const dataAsArrayWithRenamedFields = dataAsArray.map(row => renameRowsProperties(row, config))
return tablemark(dataAsArrayWithRenamedFields, config.tablemarkOptions);
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
}

@@ -112,0 +116,0 @@

@@ -11,3 +11,3 @@ import path from 'node:path';

/**
* Fetch the information about 1 package from the npm registry
* Fetch the information about one package from the (npm) registry
* @param {string} name - full name of the package

@@ -18,3 +18,2 @@ * @returns {object} with all informations about a package

const uri = path.join(config.registry, name)
// const uri = config.registry + name

@@ -21,0 +20,0 @@ debug('getPackageDataFromRepository - REQUEST %s', uri)

/**
* Create object with all fields listed in config.fields with current values about one package.
* Only fields from field list will be returned in generated object.
* Only fields from the field list will be returned in the generated object.
* If there is no value for a field in 'packageData', then the value is taken from the corresponding
* 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')

@@ -5,0 +7,0 @@ * @param config - global configuration object

{
"name": "license-report",
"version": "6.3.0",
"version": "6.4.0",
"description": "creates a short report about project's dependencies (license, url etc)",

@@ -30,3 +30,3 @@ "main": "index.js",

"eol": "^0.9.1",
"got": "^12.5.2",
"got": "^12.6.0",
"rc": "^1.2.8",

@@ -39,7 +39,7 @@ "semver": "^7.3.8",

"devDependencies": {
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"husky": "^8.0.1",
"mocha": "^10.1.0",
"nock": "^13.2.9",
"@commitlint/cli": "^17.5.1",
"@commitlint/config-conventional": "^17.4.4",
"husky": "^8.0.3",
"mocha": "^10.2.0",
"nock": "^13.3.0",
"standard-version": "^9.5.0"

@@ -46,0 +46,0 @@ },

# license report tool
![Version](https://img.shields.io/badge/version-6.3.0-blue.svg?cacheSeconds=2592000)
![Version](https://img.shields.io/badge/version-6.4.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)

@@ -18,5 +18,6 @@

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

@@ -26,4 +27,6 @@ cd your/project/

```
by default, `license-report` outputs all licenses from `dependencies`, `devDependencies`, `optionalDependencies` and `peerDependencies`.
To specify one or the other, use `--only`; e.g.
### Select dependencies:
To specify one or some dependency types, use configuration options, e.g.
```

@@ -47,3 +50,4 @@ license-report --only=dev

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

@@ -53,4 +57,4 @@ license-report --package=/path/to/package.json

#### customize a field's label:
Used as column headers in table / csv / html output. For html output the labels of all fields in the output must be unique.
### 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.
```

@@ -60,4 +64,4 @@ license-report --department.label=division

#### customize a fields default value:
Only applicable for the fields in the list later in this document (look for "Fields with data set in the configuration of license-report")
### 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")
```

@@ -67,3 +71,4 @@ license-report --department.value=ninjaSquad

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

@@ -73,3 +78,3 @@ license-report --registry=https://myregistry.com/

#### registry with authorization:
### 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:

@@ -82,3 +87,3 @@ ```

#### generate different outputs:
### Generate different outputs:
```

@@ -100,10 +105,11 @@ license-report --output=table

# see the output immediately in your browser, use hcat (npm i -g hcat)
# see the output immediately in your browser, use hcat
license-report --output=html | hcat
```
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:
### 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.
There must be at least 2 --fields options, otherwise license-report
There must be at least 2 --fields options ('name' and 'installedVersion'), otherwise license-report
will throw an error.

@@ -138,8 +144,25 @@

```
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).
#### exclude packages:
When using "custom" field, an element named like the "custom" field with 2 properties must be addes: "value" - the default value for this field - and "label - the "heading" for generated columns. Here is an example for adding the 'homepage' field:
```
"fields": [
"name",
"installedVersion",
"homepage"
],
"homepage": {
"value": 'n/a',
"label": 'Homepage'
}
```
### Exclude packages:
With the 'exclude' option, single packages can be excluded from the output.
```
license-report --exclude=async --exclude=rc
```
## Format output
### Markdown Options

@@ -186,3 +209,3 @@ 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.

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

@@ -189,0 +212,0 @@ | fieldname | column title | data source |

@@ -10,2 +10,12 @@ import assert from 'node:assert';

let projectRootPath
const fields = [
'relatedTo',
'name',
'licensePeriod',
'material',
'licenseType',
'link',
'definedVersion',
'author'
]

@@ -25,3 +35,3 @@ beforeEach(() => {

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -39,3 +49,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -54,3 +64,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -68,3 +78,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -82,3 +92,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -96,3 +106,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -117,4 +127,14 @@ assert.ok(depsIndexElement.installedVersion)

describe('addLocalPackageData with monorepo', function() {
const fields = [
'relatedTo',
'name',
'licensePeriod',
'material',
'licenseType',
'link',
'definedVersion',
'author'
]
describe('addLocalPackageData with monorepo', function() {
it('adds package data for package in root level', async () => {

@@ -131,3 +151,3 @@ const projectRootPath = path

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -149,3 +169,3 @@ assert.ok(depsIndexElement.installedVersion)

}
await addLocalPackageData(depsIndexElement, projectRootPath)
await addLocalPackageData(depsIndexElement, projectRootPath, fields)

@@ -155,2 +175,42 @@ assert.ok(depsIndexElement.installedVersion)

})
})
})
describe('addLocalPackageData with custom fields', function() {
let projectRootPath
const fields = [
'name',
'material',
'licenseType',
'homepage',
'definedVersion',
'author',
'bugs'
]
beforeEach(() => {
projectRootPath = path
.resolve(__dirname, 'fixture', 'add-local-data')
.replace(/(\s+)/g, '\\$1')
})
it('adds package data for package in root level', async () => {
const depsIndexElement = {
fullName: '@kessler/tableify',
alias: '',
name: 'tableify',
version: '^1.0.2',
scope: '@kessler'
}
await addLocalPackageData(depsIndexElement, projectRootPath, fields)
assert.ok(depsIndexElement.installedVersion)
assert.strictEqual(depsIndexElement.installedVersion, '1.0.2')
assert.ok(depsIndexElement.homepage)
assert.strictEqual(depsIndexElement.homepage, 'https://github.com/kessler/node-tableify')
assert.ok(depsIndexElement.bugs)
const expectedBugs = {
url: 'https://github.com/kessler/node-tableify/issues'
}
assert.deepStrictEqual(depsIndexElement.bugs, expectedBugs)
})
})

@@ -34,2 +34,7 @@ import assert from 'node:assert';

// test data for e2e test using custom fields
const customFieldsConfigPath = path
.resolve(__dirname, 'fixture', 'all-fields', 'license-report-config-custom-fields.json')
.replace(/(\s+)/g, '\\$1')
// test data for e2e test using the default fields and local packages

@@ -43,2 +48,15 @@ const localPackagesPackageJsonPath = path

// test data for e2e test using package.json with empty dependencies
const emptyDepsPackageJsonPath = path
.resolve(__dirname, 'fixture', 'dependencies', 'empty-dependency-package.json')
.replace(/(\s+)/g, '\\$1')
// test data for e2e test using package.json with no dependencies
const noDepsPackageJsonPath = path
.resolve(__dirname, 'fixture', 'dependencies', 'no-dependency-package.json')
.replace(/(\s+)/g, '\\$1')
// test data for e2e test using package.json with no dependencies
const subPackageJsonPath = path
.resolve(__dirname, 'fixture', 'dependencies', 'sub-deps-package.json')
.replace(/(\s+)/g, '\\$1')
const execAsPromise = util.promisify(cp.exec)

@@ -49,4 +67,4 @@

describe('end to end test for default fields', function() {
this.timeout(50000)
this.slow(4000)
this.timeout(60000)
this.slow(5000)

@@ -103,4 +121,4 @@ beforeEach(async () => {

describe('end to end test for default fields in monorepo', function() {
this.timeout(50000)
this.slow(4000)
this.timeout(60000)
this.slow(5000)

@@ -231,2 +249,112 @@ beforeEach(async () => {

describe('end to end test package without dependencies', function() {
this.timeout(50000)
this.slow(4000)
it('produce a json report for a package with empty dependencies', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${emptyDepsPackageJsonPath}`)
const result = JSON.parse(stdout)
const expectedResult = [];
await expectedOutput.addRemoteVersionsToExpectedData(expectedResult)
assert.deepStrictEqual(result, expectedResult, `expected the output to contain no entries`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
it('produce a json report for a package without dependencies', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${noDepsPackageJsonPath}`)
const result = JSON.parse(stdout)
const expectedResult = [];
await expectedOutput.addRemoteVersionsToExpectedData(expectedResult)
assert.deepStrictEqual(result, expectedResult, `expected the output to contain no entries`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
it('produce a json report for a package with sub-package without dependencies', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${subPackageJsonPath}`)
const result = JSON.parse(stdout)
const expectedResult = [ {
author: "Dan VerWeire, Yaniv Kessler",
definedVersion: "^1.0.2",
department: "kessler",
installedVersion: "1.0.2",
licensePeriod: "perpetual",
licenseType: "MIT",
link: "git+https://github.com/kessler/node-tableify.git",
material: "material",
name: "@kessler/tableify",
relatedTo: "stuff",
remoteVersion: "1.0.2"
},
{
author: "TJ Holowaychuk <tj@vision-media.ca>",
definedVersion: "^9.1.1",
department: "kessler",
installedVersion: "9.1.2",
licensePeriod: "perpetual",
licenseType: "MIT",
link: "git+https://github.com/mochajs/mocha.git",
material: "material",
name: "mocha",
relatedTo: "stuff",
remoteVersion: "9.2.2"
}
];
await expectedOutput.addRemoteVersionsToExpectedData(expectedResult)
assert.deepStrictEqual(result, expectedResult, `expected the output to contain no entries`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
it('produce a markdown report for a package with empty dependencies', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${emptyDepsPackageJsonPath} --output=markdown`)
const result = stdout
const expectedResult = '\n'
assert.deepStrictEqual(result, expectedResult, `expected the output to contain no entries`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
it('produce a markdown report for a package with no dependencies', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${noDepsPackageJsonPath} --output=markdown`)
const result = stdout
const expectedResult = '\n'
assert.deepStrictEqual(result, expectedResult, `expected the output to contain no entries`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
})
describe('end to end test for custom fields', function() {
this.timeout(50000)
this.slow(4000)
it('produce a json report with custom fields specified in config', async () => {
const { stdout, stderr } = await execAsPromise(`node ${scriptPath} --package=${allFieldsPackageJsonPath} --config=${customFieldsConfigPath}`)
const result = JSON.parse(stdout)
const expectedResult = [{
department: "kessler",
relatedTo: "stuff",
name: "semver",
licensePeriod: "perpetual",
material: "material",
licenseType: "ISC",
link: "git+https://github.com/npm/node-semver.git",
installedFrom: "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
remoteVersion: "5.7.1",
latestRemoteVersion: '7.3.7',
latestRemoteModified: '2022-07-25T16:10:58.611Z',
installedVersion: "5.4.1",
definedVersion: "^5.0.0",
author:"GitHub Inc.",
description: "The semantic version parser used by npm."
}];
await expectedOutput.addRemoteVersionsToExpectedData(expectedResult)
assert.deepStrictEqual(result, expectedResult, `expected the output to contain all the configured fields`)
assert.strictEqual(stderr, '', 'expected no warnings')
})
})
// raw data we use to generate the expected results for default fields test

@@ -233,0 +361,0 @@ const EXPECTED_DEFAULT_FIELDS_RAW_DATA = [

@@ -17,2 +17,11 @@ // During the test the env variable is set to test

// test data for test using package.json with empty dependencies
const emptyDepsPackageJsonPath = path
.resolve(__dirname, 'fixture', 'dependencies', 'empty-dependency-package.json')
.replace(/(\s+)/g, '\\$1')
// test data for test using package.json with no dependencies
const noDepsPackageJsonPath = path
.resolve(__dirname, 'fixture', 'dependencies', 'no-dependency-package.json')
.replace(/(\s+)/g, '\\$1')
describe('getDependencies', () => {

@@ -71,2 +80,16 @@ let packageJson

})
it('adds dependencies to output for empty dependencies property', () => {
const exclusions = []
let depsIndex = getDependencies(emptyDepsPackageJsonPath, exclusions)
assert.strictEqual(depsIndex.length, 0)
})
it('adds all dependency to output for missing dependencies properties', () => {
const exclusions = []
let depsIndex = getDependencies(noDepsPackageJsonPath, exclusions)
assert.strictEqual(depsIndex.length, 0)
})
});

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