@kingironman2011/license-checker 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/cli/options.d.ts +60 -4
- package/dist/cli/options.js +234 -44
- package/dist/cli/preflight.d.ts +8 -0
- package/dist/cli/preflight.js +32 -0
- package/dist/cli/usage.d.ts +1 -0
- package/dist/cli/usage.js +39 -0
- package/dist/cli.js +17 -33
- package/dist/dependencies/direct-dependencies.d.ts +10 -0
- package/dist/dependencies/direct-dependencies.js +28 -0
- package/dist/dependencies/read-installed-packages.d.ts +9 -2
- package/dist/dependencies/read-installed-packages.js +174 -52
- package/dist/dependencies/walk-dependency-tree.d.ts +19 -0
- package/dist/dependencies/walk-dependency-tree.js +38 -0
- package/dist/files/read-json.d.ts +1 -0
- package/dist/files/read-json.js +8 -0
- package/dist/index.d.ts +88 -3
- package/dist/index.js +272 -24
- package/dist/licenses/clarifications.d.ts +3 -0
- package/dist/licenses/clarifications.js +33 -0
- package/dist/licenses/collect-license-results.d.ts +26 -2
- package/dist/licenses/collect-license-results.js +321 -12
- package/dist/licenses/copyright.d.ts +1 -0
- package/dist/licenses/copyright.js +13 -0
- package/dist/licenses/detect-license-title.d.ts +1 -0
- package/dist/licenses/detect-license-title.js +145 -0
- package/dist/licenses/find-license-files.d.ts +1 -0
- package/dist/licenses/find-license-files.js +26 -0
- package/dist/licenses/package-metadata.d.ts +20 -0
- package/dist/licenses/package-metadata.js +41 -0
- package/dist/licenses/spdx-data.d.ts +4 -0
- package/dist/licenses/spdx-data.js +922 -0
- package/dist/licenses/spdx.d.ts +17 -0
- package/dist/licenses/spdx.js +394 -0
- package/dist/output/ansi.d.ts +4 -0
- package/dist/output/ansi.js +94 -0
- package/dist/output/csv.d.ts +4 -0
- package/dist/output/csv.js +50 -0
- package/dist/output/filter-attributes.d.ts +2 -0
- package/dist/output/filter-attributes.js +10 -0
- package/dist/output/format-output.d.ts +4 -0
- package/dist/output/format-output.js +81 -0
- package/dist/output/renderers.d.ts +15 -0
- package/dist/output/renderers.js +112 -0
- package/dist/output/write-output.d.ts +3 -2
- package/dist/output/write-output.js +18 -10
- package/dist/policies/license-policy.d.ts +20 -0
- package/dist/policies/license-policy.js +112 -0
- package/dist/policies/package-filters.d.ts +6 -0
- package/dist/policies/package-filters.js +56 -0
- package/dist/shared/debug.d.ts +1 -0
- package/dist/shared/debug.js +25 -0
- package/dist/shared/first-defined.d.ts +1 -0
- package/dist/shared/first-defined.js +7 -0
- package/dist/shared/semver.d.ts +1 -0
- package/dist/shared/semver.js +269 -0
- package/dist/types.d.ts +132 -20
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# License Checker
|
|
2
|
+
|
|
3
|
+
Scan a Node.js project’s production and development dependencies, print their license information, and copy discovered license files into an output directory.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 24 or newer
|
|
8
|
+
- A project with dependencies installed
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
Run the CLI directly with pnpm:
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm dlx @kingironman2011/license-checker
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install it in a project:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pnpm add -D @kingironman2011/license-checker
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Then run:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
pnpm exec license-checker
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The command scans the current directory by default. Pass a project directory to scan another project:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pnpm exec license-checker ./path/to/project
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## CLI options
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
Usage: license-checker [project-directory] [options]
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
--check List dependencies with no license metadata or license file
|
|
43
|
+
--silent, -s Do not print the license report
|
|
44
|
+
--extract, --files <dir> Copy license files into <dir>
|
|
45
|
+
--production, --prod Scan production dependencies only
|
|
46
|
+
--development, --dev Scan development dependencies only
|
|
47
|
+
--all Scan both dependency scopes (default)
|
|
48
|
+
--help, -h Show this help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
# Check production dependencies in the current directory
|
|
55
|
+
pnpm exec license-checker --production
|
|
56
|
+
|
|
57
|
+
# Find dependencies without license metadata or a license file (exits nonzero if any are found)
|
|
58
|
+
pnpm exec license-checker --check
|
|
59
|
+
|
|
60
|
+
# Copy discovered license files to ./licenses
|
|
61
|
+
pnpm exec license-checker --extract ./licenses
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
When `--check` finds dependencies whose license is unknown and which have no license files, it lists them and exits with status 1. Otherwise it reports that all dependencies have license metadata or license files. `--silent` suppresses report output; it does not change the exit status.
|
|
65
|
+
|
|
66
|
+
## Library API
|
|
67
|
+
|
|
68
|
+
The package also exports `runLicenseCheck` for use from JavaScript or TypeScript:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { runLicenseCheck } from "@kingironman2011/license-checker";
|
|
72
|
+
|
|
73
|
+
const dependencies = await runLicenseCheck({
|
|
74
|
+
start: process.cwd(),
|
|
75
|
+
production: true,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
console.log(dependencies);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Options include `start` (project directory), `production`, `development`, and `files` (directory for extracted license files). With neither scope selected, both production and development dependencies are scanned. Each result includes the package name, version, license, license file paths, and dependency scope.
|
|
82
|
+
|
|
83
|
+
## Development
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
pnpm install
|
|
87
|
+
pnpm build
|
|
88
|
+
pnpm lint
|
|
89
|
+
pnpm format:check
|
|
90
|
+
```
|
package/dist/cli/options.d.ts
CHANGED
|
@@ -1,4 +1,60 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import type { NormalizedArguments, ParsedArguments } from "../types.js";
|
|
3
|
+
export declare const knownOptions: {
|
|
4
|
+
angularCli: BooleanConstructor;
|
|
5
|
+
clarificationsFile: typeof path;
|
|
6
|
+
clarificationsMatchAll: BooleanConstructor;
|
|
7
|
+
color: BooleanConstructor;
|
|
8
|
+
csv: BooleanConstructor;
|
|
9
|
+
csvComponentPrefix: StringConstructor;
|
|
10
|
+
customPath: typeof path;
|
|
11
|
+
depth: NumberConstructor;
|
|
12
|
+
development: BooleanConstructor;
|
|
13
|
+
direct: (StringConstructor | null)[];
|
|
14
|
+
excludeLicenses: StringConstructor;
|
|
15
|
+
excludePackages: StringConstructor;
|
|
16
|
+
excludePackagesStartingWith: StringConstructor;
|
|
17
|
+
excludePrivatePackages: BooleanConstructor;
|
|
18
|
+
failOn: StringConstructor;
|
|
19
|
+
files: typeof path;
|
|
20
|
+
help: BooleanConstructor;
|
|
21
|
+
includeLicenses: StringConstructor;
|
|
22
|
+
includePackages: StringConstructor;
|
|
23
|
+
json: BooleanConstructor;
|
|
24
|
+
limitAttributes: StringConstructor;
|
|
25
|
+
markdown: BooleanConstructor;
|
|
26
|
+
nopeer: BooleanConstructor;
|
|
27
|
+
onlyAllow: StringConstructor;
|
|
28
|
+
onlyunknown: BooleanConstructor;
|
|
29
|
+
out: typeof path;
|
|
30
|
+
plainVertical: BooleanConstructor;
|
|
31
|
+
production: BooleanConstructor;
|
|
32
|
+
relativeLicensePath: BooleanConstructor;
|
|
33
|
+
relativeModulePath: BooleanConstructor;
|
|
34
|
+
start: StringConstructor;
|
|
35
|
+
summary: BooleanConstructor;
|
|
36
|
+
unknown: BooleanConstructor;
|
|
37
|
+
version: BooleanConstructor;
|
|
38
|
+
};
|
|
39
|
+
export declare const shortHands: {
|
|
40
|
+
h: string[];
|
|
41
|
+
v: string[];
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {ParsedArguments & {
|
|
45
|
+
* color: boolean,
|
|
46
|
+
* direct: number,
|
|
47
|
+
* relativeLicensePath: boolean,
|
|
48
|
+
* relativeModulePath: boolean,
|
|
49
|
+
* start: string,
|
|
50
|
+
* depth: number
|
|
51
|
+
* }} ArgumentsWithDefaults Parsed command-line arguments with defaults applied.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Applies default values to parsed command-line arguments.
|
|
55
|
+
*
|
|
56
|
+
* @param {ParsedArguments} parsedArguments Parsed command-line arguments.
|
|
57
|
+
* @returns {ArgumentsWithDefaults} Parsed command-line arguments with defaults applied.
|
|
58
|
+
*/
|
|
59
|
+
export declare function setDefaultArguments(parsedArguments?: ParsedArguments): NormalizedArguments;
|
|
60
|
+
export declare function getNormalizedArguments(args?: string[]): NormalizedArguments;
|
package/dist/cli/options.js
CHANGED
|
@@ -1,56 +1,246 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
import { supportsBasicColor } from "../output/ansi.js";
|
|
3
|
+
export const knownOptions = {
|
|
4
|
+
angularCli: Boolean,
|
|
5
|
+
clarificationsFile: path,
|
|
6
|
+
clarificationsMatchAll: Boolean,
|
|
7
|
+
color: Boolean,
|
|
8
|
+
csv: Boolean,
|
|
9
|
+
csvComponentPrefix: String,
|
|
10
|
+
customPath: path,
|
|
11
|
+
depth: Number, // Meant to replace the misleading "--direct" option
|
|
12
|
+
development: Boolean,
|
|
13
|
+
direct: [String, null],
|
|
14
|
+
excludeLicenses: String,
|
|
15
|
+
excludePackages: String,
|
|
16
|
+
excludePackagesStartingWith: String,
|
|
17
|
+
excludePrivatePackages: Boolean,
|
|
18
|
+
failOn: String,
|
|
19
|
+
files: path,
|
|
20
|
+
help: Boolean,
|
|
21
|
+
includeLicenses: String,
|
|
22
|
+
includePackages: String,
|
|
23
|
+
json: Boolean,
|
|
24
|
+
limitAttributes: String,
|
|
25
|
+
markdown: Boolean,
|
|
26
|
+
nopeer: Boolean,
|
|
27
|
+
onlyAllow: String,
|
|
28
|
+
onlyunknown: Boolean,
|
|
29
|
+
out: path,
|
|
30
|
+
plainVertical: Boolean,
|
|
31
|
+
production: Boolean,
|
|
32
|
+
relativeLicensePath: Boolean,
|
|
33
|
+
relativeModulePath: Boolean,
|
|
34
|
+
start: String,
|
|
35
|
+
summary: Boolean,
|
|
36
|
+
unknown: Boolean,
|
|
37
|
+
version: Boolean,
|
|
38
|
+
};
|
|
39
|
+
export const shortHands = {
|
|
40
|
+
h: ["--help"],
|
|
41
|
+
v: ["--version"],
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {Object} ParsedArguments Parsed command-line arguments.
|
|
45
|
+
* @property {boolean=} angularCli Output in Angular CLI-compatible plain vertical format.
|
|
46
|
+
* @property {string=} clarificationsFile Path to a license clarifications file.
|
|
47
|
+
* @property {boolean=} clarificationsMatchAll Require every clarification to match a package.
|
|
48
|
+
* @property {(boolean | null)=} color Colorize output.
|
|
49
|
+
* @property {boolean=} csv Output in CSV format.
|
|
50
|
+
* @property {string=} csvComponentPrefix Prefix column for component in CSV format.
|
|
51
|
+
* @property {string=} customPath Path to a JSON file that defines a custom output format.
|
|
52
|
+
* @property {(string | number)=} depth Recurse dependencies up to a specific depth.
|
|
53
|
+
* @property {boolean=} development Only show development dependencies.
|
|
54
|
+
* @property {(string | boolean | number | null)=} direct Look for direct dependencies only.
|
|
55
|
+
* @property {string=} excludeLicenses Exclude modules which licenses are in the comma-separated list from the output.
|
|
56
|
+
* @property {string=} excludePackages Restrict output to the packages not in the semicolon-separated list.
|
|
57
|
+
* @property {string=} excludePackagesStartingWith Exclude modules starting with a specific string.
|
|
58
|
+
* @property {boolean=} excludePrivatePackages Restrict output to not include any package marked as private.
|
|
59
|
+
* @property {string=} failOn Fail on the first occurrence of a license in the semicolon-separated list.
|
|
60
|
+
* @property {string=} files Path to write output files to.
|
|
61
|
+
* @property {boolean=} help Show help output.
|
|
62
|
+
* @property {string=} includeLicenses Include modules which licenses are in the comma-separated list in the output.
|
|
63
|
+
* @property {string=} includePackages Restrict output to the packages in the semicolon-separated list.
|
|
64
|
+
* @property {boolean=} json Output in JSON format.
|
|
65
|
+
* @property {string=} limitAttributes Restrict formatted JSON output to a specific set of fields.
|
|
66
|
+
* @property {boolean=} markdown Output in Markdown format.
|
|
67
|
+
* @property {boolean=} nopeer Ignore peerDependencies.
|
|
68
|
+
* @property {string=} onlyAllow Fail on the first occurrence of a license not in the semicolon-separated list.
|
|
69
|
+
* @property {boolean=} onlyunknown Only list packages with unknown or guessed licenses.
|
|
70
|
+
* @property {string=} out Write the data to a specific file.
|
|
71
|
+
* @property {boolean=} plainVertical Output in plain vertical format.
|
|
72
|
+
* @property {boolean=} production Only show production dependencies.
|
|
73
|
+
* @property {boolean=} relativeLicensePath Output license file locations as relative paths.
|
|
74
|
+
* @property {boolean=} relativeModulePath Output module locations as relative paths.
|
|
75
|
+
* @property {string=} start Path to start checking dependencies from.
|
|
76
|
+
* @property {boolean=} summary Output a summary of the license usage.
|
|
77
|
+
* @property {boolean=} unknown Report guessed licenses as unknown licenses.
|
|
78
|
+
* @property {boolean=} version Show version output.
|
|
79
|
+
*/
|
|
80
|
+
function normalizeArgv(args = process.argv) {
|
|
81
|
+
if (Array.isArray(args) && (args.length === 0 || args[0]?.startsWith("-"))) {
|
|
82
|
+
return [process.execPath, "license-checker-rseidelsohn", ...args];
|
|
83
|
+
}
|
|
84
|
+
return args;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parses command-line arguments.
|
|
88
|
+
*
|
|
89
|
+
* @param {string[]} [args] Command-line arguments to parse.
|
|
90
|
+
* @returns {ParsedArguments} Parsed command-line arguments.
|
|
91
|
+
*/
|
|
92
|
+
function parseArguments(args = process.argv) {
|
|
93
|
+
const argv = normalizeArgv(args).slice(2);
|
|
94
|
+
const parsedArguments = {};
|
|
95
|
+
const optionNames = Object.keys(knownOptions);
|
|
96
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
97
|
+
const argument = argv[index];
|
|
98
|
+
if (!argument?.startsWith("-"))
|
|
99
|
+
continue;
|
|
100
|
+
if (/^-{2,}$/.test(argument))
|
|
101
|
+
break;
|
|
102
|
+
const equalIndex = argument.indexOf("=");
|
|
103
|
+
const hasEquals = equalIndex >= 0;
|
|
104
|
+
let name = argument.replace(/^-+/, "");
|
|
105
|
+
let valueFromEquals;
|
|
106
|
+
if (hasEquals) {
|
|
107
|
+
valueFromEquals = name.slice(name.indexOf("=") + 1);
|
|
108
|
+
name = name.slice(0, name.indexOf("="));
|
|
16
109
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
110
|
+
if (name === "h" || name === "v")
|
|
111
|
+
name = name === "h" ? "help" : "version";
|
|
112
|
+
else if (name.length > 1 && !optionNames.includes(name)) {
|
|
113
|
+
const matches = optionNames.filter((option) => option.startsWith(name));
|
|
114
|
+
if (matches.length === 1)
|
|
115
|
+
name = matches[0];
|
|
20
116
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
117
|
+
let negated = false;
|
|
118
|
+
while (name.toLowerCase().startsWith("no-")) {
|
|
119
|
+
negated = !negated;
|
|
120
|
+
name = name.slice(3);
|
|
24
121
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
index
|
|
122
|
+
const kind = knownOptions[name];
|
|
123
|
+
const isBoolean = kind === Boolean;
|
|
124
|
+
let value;
|
|
125
|
+
if (isBoolean || negated) {
|
|
126
|
+
value = !negated;
|
|
127
|
+
const next = argv[index + 1];
|
|
128
|
+
if (!hasEquals && (next === "true" || next === "false")) {
|
|
129
|
+
value = next === "true";
|
|
130
|
+
index += 1;
|
|
131
|
+
}
|
|
132
|
+
if (hasEquals) {
|
|
133
|
+
value = !(valueFromEquals === "false" ||
|
|
134
|
+
valueFromEquals === "0" ||
|
|
135
|
+
valueFromEquals === "null");
|
|
136
|
+
}
|
|
137
|
+
if (negated && Array.isArray(kind) && kind.includes(null))
|
|
138
|
+
value = null;
|
|
31
139
|
}
|
|
32
|
-
else
|
|
33
|
-
|
|
34
|
-
|
|
140
|
+
else {
|
|
141
|
+
const next = hasEquals ? valueFromEquals : argv[index + 1];
|
|
142
|
+
if (next === undefined || next.startsWith("-")) {
|
|
143
|
+
value = kind === String ? "" : true;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
value = next;
|
|
147
|
+
index += 1;
|
|
148
|
+
}
|
|
149
|
+
if (kind === Number && !Number.isNaN(Number(value)))
|
|
150
|
+
value = Number(value);
|
|
151
|
+
if (kind === path && value !== true)
|
|
152
|
+
value = path.resolve(String(value));
|
|
153
|
+
if (kind === path && value === true)
|
|
154
|
+
continue;
|
|
35
155
|
}
|
|
36
|
-
|
|
37
|
-
|
|
156
|
+
if (kind === Number &&
|
|
157
|
+
typeof value === "string" &&
|
|
158
|
+
Number.isNaN(Number(value)))
|
|
159
|
+
continue;
|
|
160
|
+
parsedArguments[name] = value;
|
|
161
|
+
}
|
|
162
|
+
return parsedArguments;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Converts a value for the "--direct" option into a number.
|
|
166
|
+
*
|
|
167
|
+
* The "--direct" option is meant to accept either a Boolean or a Number. Either of those values will then be taken for
|
|
168
|
+
* determining the depth:
|
|
169
|
+
* - Passing in no value or leaving the parameter off will be interpreted as Infinity
|
|
170
|
+
* - Passing in true will be interpreted as Infinity
|
|
171
|
+
* - Passing in false will be interpreted as 0
|
|
172
|
+
* - Passing in a number will be interpreted as that number
|
|
173
|
+
* - Passing in any other value that can't be recognized as a number will be interpreted as Infinity
|
|
174
|
+
*
|
|
175
|
+
* @param {boolean | number | string | undefined} value
|
|
176
|
+
* @returns number
|
|
177
|
+
*/
|
|
178
|
+
function toDepthNumber(value = Number.POSITIVE_INFINITY) {
|
|
179
|
+
switch (typeof value) {
|
|
180
|
+
case "string":
|
|
181
|
+
return depthStringToNumber(value);
|
|
182
|
+
case "boolean":
|
|
183
|
+
return value ? Number.POSITIVE_INFINITY : 0;
|
|
184
|
+
case "number":
|
|
185
|
+
return Math.max(0, value);
|
|
186
|
+
default:
|
|
187
|
+
return Number.POSITIVE_INFINITY;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function depthStringToNumber(depthString) {
|
|
191
|
+
const lowered = depthString.toLowerCase();
|
|
192
|
+
let numberValue;
|
|
193
|
+
if (lowered === "true") {
|
|
194
|
+
numberValue = Number.POSITIVE_INFINITY;
|
|
195
|
+
}
|
|
196
|
+
else if (lowered === "false") {
|
|
197
|
+
numberValue = 0;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
numberValue = Number.parseInt(lowered, 10);
|
|
201
|
+
if (Number.isNaN(numberValue)) {
|
|
202
|
+
numberValue = Number.POSITIVE_INFINITY;
|
|
38
203
|
}
|
|
39
204
|
else {
|
|
40
|
-
|
|
205
|
+
numberValue = Math.max(0, numberValue);
|
|
41
206
|
}
|
|
42
207
|
}
|
|
43
|
-
return
|
|
208
|
+
return numberValue;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* @typedef {ParsedArguments & {
|
|
212
|
+
* color: boolean,
|
|
213
|
+
* direct: number,
|
|
214
|
+
* relativeLicensePath: boolean,
|
|
215
|
+
* relativeModulePath: boolean,
|
|
216
|
+
* start: string,
|
|
217
|
+
* depth: number
|
|
218
|
+
* }} ArgumentsWithDefaults Parsed command-line arguments with defaults applied.
|
|
219
|
+
*/
|
|
220
|
+
/**
|
|
221
|
+
* Applies default values to parsed command-line arguments.
|
|
222
|
+
*
|
|
223
|
+
* @param {ParsedArguments} parsedArguments Parsed command-line arguments.
|
|
224
|
+
* @returns {ArgumentsWithDefaults} Parsed command-line arguments with defaults applied.
|
|
225
|
+
*/
|
|
226
|
+
export function setDefaultArguments(parsedArguments = {}) {
|
|
227
|
+
const argumentsWithDefaults = { ...parsedArguments };
|
|
228
|
+
if (argumentsWithDefaults.color === null ||
|
|
229
|
+
argumentsWithDefaults.color === undefined) {
|
|
230
|
+
argumentsWithDefaults.color = supportsBasicColor();
|
|
231
|
+
}
|
|
232
|
+
if (argumentsWithDefaults.json ||
|
|
233
|
+
argumentsWithDefaults.markdown ||
|
|
234
|
+
argumentsWithDefaults.csv) {
|
|
235
|
+
argumentsWithDefaults.color = false;
|
|
236
|
+
}
|
|
237
|
+
argumentsWithDefaults.start = argumentsWithDefaults.start ?? process.cwd();
|
|
238
|
+
argumentsWithDefaults.relativeLicensePath = Boolean(argumentsWithDefaults.relativeLicensePath);
|
|
239
|
+
argumentsWithDefaults.relativeModulePath = Boolean(argumentsWithDefaults.relativeModulePath);
|
|
240
|
+
// "--depth" should replace "--direct", as it is better understandable:
|
|
241
|
+
argumentsWithDefaults.direct = toDepthNumber(argumentsWithDefaults.depth ?? argumentsWithDefaults.direct);
|
|
242
|
+
return argumentsWithDefaults;
|
|
44
243
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Options:
|
|
49
|
-
--check List dependencies with no license metadata or license file
|
|
50
|
-
--silent, -s Do not print the license report
|
|
51
|
-
--extract, --files <dir> Copy license files into <dir>
|
|
52
|
-
--production, --prod Scan production dependencies only
|
|
53
|
-
--development, --dev Scan development dependencies only
|
|
54
|
-
--all Scan both dependency scopes (default)
|
|
55
|
-
--help, -h Show this help`);
|
|
244
|
+
export function getNormalizedArguments(args = process.argv) {
|
|
245
|
+
return setDefaultArguments(parseArguments(args));
|
|
56
246
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
2
|
+
import { usageMessage } from "./usage.js";
|
|
3
|
+
const version = packageJson.version;
|
|
4
|
+
export const exitProcessOrWarnIfNeeded = ({ unknownArgs, parsedArgs, }) => {
|
|
5
|
+
if (unknownArgs.length) {
|
|
6
|
+
console.error(`license-checker-rseidelsohn@${version}`, "\n");
|
|
7
|
+
console.error(`Error: Unknown option${unknownArgs.length > 1 ? "s" : ""}: ${unknownArgs
|
|
8
|
+
.map((unknownArg) => `'${unknownArg}'`)
|
|
9
|
+
.join(", ")}`);
|
|
10
|
+
console.error(" Possibly a typo?", "\n");
|
|
11
|
+
console.error(usageMessage, "\n");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
if (parsedArgs.help) {
|
|
15
|
+
console.log(`license-checker-rseidelsohn@${version}`);
|
|
16
|
+
console.log(usageMessage, "\n");
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
if (parsedArgs.version) {
|
|
20
|
+
console.error(version);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
if (parsedArgs.failOn && parsedArgs.onlyAllow) {
|
|
24
|
+
console.error("Error: --failOn and --onlyAllow can not be used at the same time. Choose one or the other.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
const hasFailArgs = parsedArgs.failOn ?? parsedArgs.onlyAllow;
|
|
28
|
+
if (hasFailArgs && hasFailArgs.indexOf(",") >= 0) {
|
|
29
|
+
const argName = parsedArgs.failOn ? "failOn" : "onlyAllow";
|
|
30
|
+
console.warn(`Warning: The --${argName} argument takes semicolons as delimeters instead of commas (some license names can contain commas)`);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const usageMessage: string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const usageMessage = [
|
|
2
|
+
"All CLI options in alphabetical order:",
|
|
3
|
+
"",
|
|
4
|
+
" --angularCli: is just a synonym for --plainVertical",
|
|
5
|
+
" --clarificationsFile [filepath]: A file that describe the license clarifications for each package, see clarificationExample.json, any field available to the customFormat option can be clarified. Can also be used to specify a subregion of a package's license file (instead reading the entire file)",
|
|
6
|
+
" --clarificationsMatchAll: fail if any clarification entry was not used",
|
|
7
|
+
" --color: colorize terminal tree output",
|
|
8
|
+
" --csv: output in csv format",
|
|
9
|
+
" --csvComponentPrefix: column prefix for components in csv file",
|
|
10
|
+
" --customPath: to add a custom Format file in JSON",
|
|
11
|
+
' --depth [number]: look for "number" of levels of dependencies - overrides the ambiguously named "--direct" option',
|
|
12
|
+
" --development: only show development dependencies",
|
|
13
|
+
' --direct [boolean|number]: look for direct dependencies only if "true" or look for "number" of levels of dependencies',
|
|
14
|
+
" --excludeLicenses [list]: exclude modules which licenses are in the comma-separated list from the output",
|
|
15
|
+
' --excludePackages [list]: restrict output to the packages (either "package@fullversion" or "package@majorversion" or only "package") NOT in the semicolon-seperated list',
|
|
16
|
+
" --excludePackagesStartingWith [list]: excludes packages starting with anything in the semicolon-separated list",
|
|
17
|
+
" --excludePrivatePackages: restrict output to not include any package marked as private",
|
|
18
|
+
" --failOn [list]: fail (exit with code 1) on the first occurrence of the licenses of the semicolon-separated list",
|
|
19
|
+
" --files [path]: copy all license files to path and rename them to `module-name`@`version`-LICENSE.txt",
|
|
20
|
+
" --help (-h): The text you are reading right now :)",
|
|
21
|
+
" --includeLicenses [list]: restrict output to the packages of which the licenses are included in the comma-separated list from the output",
|
|
22
|
+
' --includePackages [list]: restrict output to the packages (either "package@fullversion" or "package@majorversion" or only "package") in the semicolon-seperated list',
|
|
23
|
+
" --json: output in json format",
|
|
24
|
+
" --limitAttributes [list]: limit the attributes to be output",
|
|
25
|
+
" --markdown: output in markdown format",
|
|
26
|
+
" --nopeer: skip peer dependencies in output",
|
|
27
|
+
" --onlyAllow [list]: fail (exit with code 1) on the first occurrence of the licenses not in the semicolon-seperated list",
|
|
28
|
+
" --onlyunknown: only list packages with unknown or guessed licenses",
|
|
29
|
+
" --out [filepath]: write the data to a specific file",
|
|
30
|
+
" --plainVertical: output in plain vertical format like [Angular CLI does](https://angular.io/3rdpartylicenses.txt)",
|
|
31
|
+
" --production: only show production dependencies",
|
|
32
|
+
" --relativeLicensePath: output the location of the license files as relative paths",
|
|
33
|
+
" --relativeModulePath: output the location of the module files as relative paths",
|
|
34
|
+
" --start [filepath]: path of the initial json to look for",
|
|
35
|
+
" --summary: output a summary of the license usage",
|
|
36
|
+
" --unknown: report guessed licenses as unknown licenses",
|
|
37
|
+
" --version (-v): The current version",
|
|
38
|
+
"",
|
|
39
|
+
].join("\n");
|
package/dist/cli.js
CHANGED
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { getNormalizedArguments } from "./cli/options.js";
|
|
2
|
+
import { getNormalizedArguments, knownOptions } from "./cli/options.js";
|
|
3
|
+
import { exitProcessOrWarnIfNeeded } from "./cli/preflight.js";
|
|
5
4
|
import { runLicenseCheck } from "./index.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (options.check) {
|
|
17
|
-
if (missing.length > 0) {
|
|
18
|
-
console.log(`Found ${missing.length} dependencies with missing licenses:\n`);
|
|
19
|
-
for (const item of missing)
|
|
20
|
-
console.log(`${item.name}@${item.version}`);
|
|
5
|
+
import { colorizeOutput, getFormattedOutput, shouldColorizeOutput, } from "./output/format-output.js";
|
|
6
|
+
const parsedArgs = getNormalizedArguments();
|
|
7
|
+
const known = Object.keys(knownOptions);
|
|
8
|
+
const unknownArgs = Object.keys(parsedArgs).filter((arg) => !known.includes(arg));
|
|
9
|
+
exitProcessOrWarnIfNeeded({ unknownArgs, parsedArgs });
|
|
10
|
+
try {
|
|
11
|
+
const foundLicensesJson = await runLicenseCheck(parsedArgs);
|
|
12
|
+
if (!parsedArgs.out) {
|
|
13
|
+
if (shouldColorizeOutput(parsedArgs)) {
|
|
14
|
+
colorizeOutput(foundLicensesJson);
|
|
21
15
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
return;
|
|
16
|
+
const formattedOutput = getFormattedOutput(foundLicensesJson, parsedArgs);
|
|
17
|
+
console.log(formattedOutput);
|
|
26
18
|
}
|
|
27
|
-
console.log(`Found ${items.length} dependencies:\n`);
|
|
28
|
-
for (const item of items)
|
|
29
|
-
console.log(`${item.name}@${item.version} ${item.license}`);
|
|
30
|
-
if (options.files)
|
|
31
|
-
console.log(`\nLicense files copied to ${options.files}`);
|
|
32
19
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
console.error(error instanceof Error ? error.message : error);
|
|
37
|
-
process.exitCode = 1;
|
|
38
|
-
});
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(error instanceof Error ? error.message : error);
|
|
22
|
+
process.exitCode = 1;
|
|
39
23
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DependencyPackage, LicenseCheckOptions } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* This function has a wanted side effect, as it modifies the package tree that is passed by reference.
|
|
4
|
+
*
|
|
5
|
+
* The depth attribute set in the options parameter here - which is defined by setting the `--direct` flag - is of
|
|
6
|
+
* no use with npm < 3, as the older npm versions flattened all dependencies into one single directory. So in
|
|
7
|
+
* order to make `--direct` work with older versions of npm, we need to filter out all non-dependencies from
|
|
8
|
+
* the result.
|
|
9
|
+
*/
|
|
10
|
+
export declare function deleteNonDirectDependencies({ _dependencies: directDependencies, dependencies: allDependencies, devDependencies, }: DependencyPackage, options: Pick<LicenseCheckOptions, "production" | "development">): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This function has a wanted side effect, as it modifies the package tree that is passed by reference.
|
|
3
|
+
*
|
|
4
|
+
* The depth attribute set in the options parameter here - which is defined by setting the `--direct` flag - is of
|
|
5
|
+
* no use with npm < 3, as the older npm versions flattened all dependencies into one single directory. So in
|
|
6
|
+
* order to make `--direct` work with older versions of npm, we need to filter out all non-dependencies from
|
|
7
|
+
* the result.
|
|
8
|
+
*/
|
|
9
|
+
export function deleteNonDirectDependencies({ _dependencies: directDependencies = {}, dependencies: allDependencies = {}, devDependencies = {}, }, options) {
|
|
10
|
+
const allDependenciesArray = Object.keys(allDependencies);
|
|
11
|
+
const directDependenciesArray = Object.keys(directDependencies);
|
|
12
|
+
const devDependenciesArray = Object.keys(devDependencies);
|
|
13
|
+
let wantedDependenciesArray = [];
|
|
14
|
+
if (options.production && !options.development) {
|
|
15
|
+
wantedDependenciesArray = directDependenciesArray.filter((directDependency) => !devDependenciesArray.includes(directDependency));
|
|
16
|
+
}
|
|
17
|
+
else if (!options.production && options.development) {
|
|
18
|
+
wantedDependenciesArray = devDependenciesArray;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
wantedDependenciesArray = directDependenciesArray;
|
|
22
|
+
}
|
|
23
|
+
allDependenciesArray.forEach((currentDependency) => {
|
|
24
|
+
if (!wantedDependenciesArray.includes(currentDependency)) {
|
|
25
|
+
delete allDependencies[currentDependency];
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { DependencyPackage } from "../types.js";
|
|
2
|
+
interface ReadOptions {
|
|
3
|
+
depth?: number | boolean;
|
|
4
|
+
dev?: boolean;
|
|
5
|
+
nopeer?: boolean;
|
|
6
|
+
log?: (...args: unknown[]) => void;
|
|
7
|
+
}
|
|
8
|
+
declare const readInstalledPackages: (folder: string, options?: ReadOptions) => Promise<DependencyPackage>;
|
|
9
|
+
export default readInstalledPackages;
|