@callstack/licenses 0.2.1

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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/build/common.d.ts +71 -0
  4. package/build/common.js +308 -0
  5. package/build/index.d.ts +3 -0
  6. package/build/index.js +42 -0
  7. package/build/types/AboutLibrariesLibraryJsonPayload.d.ts +13 -0
  8. package/build/types/AboutLibrariesLibraryJsonPayload.js +2 -0
  9. package/build/types/AboutLibrariesLicenseJsonPayload.d.ts +6 -0
  10. package/build/types/AboutLibrariesLicenseJsonPayload.js +2 -0
  11. package/build/types/AboutLibrariesLikePackageInfo.d.ts +7 -0
  12. package/build/types/AboutLibrariesLikePackageInfo.js +2 -0
  13. package/build/types/AggregatedLicensesObj.d.ts +6 -0
  14. package/build/types/AggregatedLicensesObj.js +2 -0
  15. package/build/types/DependencyType.d.ts +3 -0
  16. package/build/types/DependencyType.js +2 -0
  17. package/build/types/LicenseObj.d.ts +24 -0
  18. package/build/types/LicenseObj.js +2 -0
  19. package/build/types/LicensePlistPayload.d.ts +7 -0
  20. package/build/types/LicensePlistPayload.js +2 -0
  21. package/build/types/ScanPackageCallContext.d.ts +25 -0
  22. package/build/types/ScanPackageCallContext.js +2 -0
  23. package/build/types/ScanPackageOptions.d.ts +24 -0
  24. package/build/types/ScanPackageOptions.js +2 -0
  25. package/build/types/index.d.ts +9 -0
  26. package/build/types/index.js +25 -0
  27. package/build/utils/index.d.ts +4 -0
  28. package/build/utils/index.js +40 -0
  29. package/build/utils/miscUtils.d.ts +6 -0
  30. package/build/utils/miscUtils.js +39 -0
  31. package/build/utils/packageUtils.d.ts +26 -0
  32. package/build/utils/packageUtils.js +100 -0
  33. package/build/utils/repositoryUtils.d.ts +1 -0
  34. package/build/utils/repositoryUtils.js +18 -0
  35. package/build/utils/yamlUtils.d.ts +4 -0
  36. package/build/utils/yamlUtils.js +64 -0
  37. package/package.json +67 -0
  38. package/src/common.ts +384 -0
  39. package/src/index.ts +3 -0
  40. package/src/types/AboutLibrariesLibraryJsonPayload.ts +10 -0
  41. package/src/types/AboutLibrariesLicenseJsonPayload.ts +6 -0
  42. package/src/types/AboutLibrariesLikePackageInfo.ts +8 -0
  43. package/src/types/AggregatedLicensesObj.ts +7 -0
  44. package/src/types/DependencyType.ts +3 -0
  45. package/src/types/LicenseObj.ts +34 -0
  46. package/src/types/LicensePlistPayload.ts +7 -0
  47. package/src/types/ScanPackageCallContext.ts +30 -0
  48. package/src/types/ScanPackageOptions.ts +29 -0
  49. package/src/types/index.ts +9 -0
  50. package/src/utils/index.ts +4 -0
  51. package/src/utils/miscUtils.ts +42 -0
  52. package/src/utils/packageUtils.ts +103 -0
  53. package/src/utils/repositoryUtils.ts +17 -0
  54. package/src/utils/yamlUtils.ts +73 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Callstack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # @callstack/licenses
2
+
3
+ ## Features
4
+
5
+ - 🔍 Scan and aggregate license information from your project dependencies
6
+ - 📝 Generate license reports in a format of choice (JSON, Markdown, raw text, AboutLibraries-compatible JSON metadata)
7
+ - 🔄 Support for both direct and transitive dependencies
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @callstack/licenses
13
+ ```
14
+
15
+ ## Programmatic Usage
16
+
17
+ You can use `@callstack/licenses` programmatically in your Node.js applications. Here's a basic example of how to use it:
18
+
19
+ ```typescript
20
+ import {
21
+ generateAboutLibrariesNPMOutput,
22
+ generateLicensePlistNPMOutput,
23
+ scanDependencies,
24
+ Types,
25
+ } from '@callstack/licenses';
26
+ import * as md from 'ts-markdown-builder';
27
+
28
+ // apart from dependencies, also include devDependencies, but only from the root package.json;
29
+ // also, include all transitive dependencies & optional dependencies
30
+ const optionsFactory: Types.ScanPackageOptionsFactory = ({ isRoot }) => ({
31
+ includeDevDependencies: isRoot,
32
+ includeTransitiveDependencies: true,
33
+ includeOptionalDependencies: true,
34
+ });
35
+
36
+ // scan dependencies of a package
37
+ const licenses = scanDependencies(packageJsonPath, optionsFactory);
38
+
39
+ // generate AboutLibraries-compatible JSON metadata
40
+ const aboutLibrariesCompatibleReport = generateAboutLibrariesNPMOutput(licenses);
41
+
42
+ // generate LicensePlist-compatible metadata
43
+ const licensePlistReport = generateLicensePlistNPMOutput(licenses, iosProjectPath);
44
+
45
+ // generate a Markdown report
46
+ const markdownString = md
47
+ .joinBlocks(
48
+ Object.entries(licenses)
49
+ .flatMap(([packageKey, { name: packageName, version, author, content, description, file, type, url }]) => [
50
+ md.heading(packageName, { level: 2 }),
51
+ '\n',
52
+ `Version: ${version}<br/>\n`,
53
+ url ? `URL: ${url}<br/>\n` : '',
54
+ author ? `Author: ${author}<br/>\n\n` : '',
55
+ content ?? '',
56
+ '\n',
57
+ description ? `Description: ${description}\n` : '',
58
+ file ? `\nFile: ${file}\n` : '',
59
+ type ? `Type: ${type}` : '',
60
+ '\n',
61
+ md.horizontalRule,
62
+ ])
63
+ .join('\n'),
64
+ )
65
+ .toString();
66
+ ```
67
+
68
+ ## API Documentation
69
+
70
+ The API documentation is published under: https://callstackincubator.github.io/react-native-legal/api/.
71
+
72
+ ## Contributing
73
+
74
+ This package is consumed by other packages in the monorepo by its build outputs, so everytime it is modified, you need to rebuild the package. This can be done once by running `yarn build`, or by running `yarn dev` to run `tsc` in watch mode. All this is described in the [Contributing Guide](../../CONTRIBUTING.md).
@@ -0,0 +1,71 @@
1
+ import type { AboutLibrariesLikePackageInfo, AggregatedLicensesObj, ScanPackageOptionsFactory } from './types';
2
+ /**
3
+ * Scans `package.json` and searches for all packages under `dependencies` field. Supports monorepo projects.
4
+ *
5
+ * @param appPackageJsonPath Path to the `package.json` file of the application
6
+ * @param scanOptionsFactory Factory function to create scan options for dependencies; defaults to {@link PackageUtils.legacyDefaultScanPackageOptionsFactory}
7
+ * @returns Aggregated licenses object containing all scanned dependencies and their license information
8
+ */
9
+ export declare function scanDependencies(appPackageJsonPath: string, scanOptionsFactory?: ScanPackageOptionsFactory): AggregatedLicensesObj;
10
+ /**
11
+ * Generates LicensePlist-compatible metadata for NPM dependencies as a YAML string.
12
+ *
13
+ * To write a file directly, use `writeLicensePlistNPMOutput` function.
14
+ *
15
+ * @param licenses Scanned NPM licenses
16
+ * @param iosProjectPath Path to the iOS project directory
17
+ * @see {@link writeLicensePlistNPMOutput}
18
+ */
19
+ export declare function generateLicensePlistNPMOutput(licenses: AggregatedLicensesObj, iosProjectPath: string): string;
20
+ /**
21
+ * Writes LicensePlist-compatible metadata for NPM dependencies to a file
22
+ *
23
+ * This will take scanned NPM licenses and produce following output inside iOS project's directory:
24
+ *
25
+ * ```
26
+ * | - ios
27
+ * | ---- myawesomeapp
28
+ * | ---- myawesomeapp.xcodeproj
29
+ * | ---- myawesomeapp.xcodeworkspace
30
+ * | ---- license_plist.yml <--- generated LicensePlist config with NPM dependencies
31
+ * | ---- Podfile
32
+ * | ---- Podfile.lock
33
+ * ```
34
+ *
35
+ * @param licenses Scanned NPM licenses
36
+ * @param iosProjectPath Path to the iOS project directory
37
+ * @param plistLikeOutput Optional pre-generated string output to use instead of generating it using `generateLicensePlistNPMOutput`
38
+ * @see {@link generateLicensePlistNPMOutput}
39
+ */
40
+ export declare function writeLicensePlistNPMOutput(licenses: AggregatedLicensesObj, iosProjectPath: string, plistLikeOutput?: string): void;
41
+ /**
42
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
43
+ *
44
+ * This will take scanned NPM licenses and produce output that can be modified and/or written to the Android project files.
45
+ *
46
+ * @param licenses Scanned NPM licenses
47
+ * @returns Array of AboutLibrariesLikePackage objects, each representing a NPM dependency
48
+ * @see {@link writeAboutLibrariesNPMOutput}
49
+ */
50
+ export declare function generateAboutLibrariesNPMOutput(licenses: AggregatedLicensesObj): AboutLibrariesLikePackageInfo[];
51
+ /**
52
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
53
+ *
54
+ * This will take scanned NPM licenses and produce following output inside android project's directory:
55
+ *
56
+ * ```
57
+ * | - android
58
+ * | ---- app
59
+ * | ---- config <--- generated AboutLibraries config directory
60
+ * | ------- libraries <--- generated directory with JSON files list of NPM dependencies
61
+ * | ------- licenses <--- generated directory with JSON files list of used licenses
62
+ * | ---- build.gradle
63
+ * | ---- settings.gradle
64
+ * ```
65
+ *
66
+ * @param licenses Scanned NPM licenses
67
+ * @param androidProjectPath Path to the Android project directory
68
+ * @param aboutLibrariesLikeOutput Optional pre-generated output to use instead of generating it using `generateAboutLibrariesNPMOutput`
69
+ * @see {@link generateAboutLibrariesNPMOutput}
70
+ */
71
+ export declare function writeAboutLibrariesNPMOutput(licenses: AggregatedLicensesObj, androidProjectPath: string, aboutLibrariesLikeOutput?: AboutLibrariesLikePackageInfo[]): void;
@@ -0,0 +1,308 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.scanDependencies = scanDependencies;
7
+ exports.generateLicensePlistNPMOutput = generateLicensePlistNPMOutput;
8
+ exports.writeLicensePlistNPMOutput = writeLicensePlistNPMOutput;
9
+ exports.generateAboutLibrariesNPMOutput = generateAboutLibrariesNPMOutput;
10
+ exports.writeAboutLibrariesNPMOutput = writeAboutLibrariesNPMOutput;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const glob_1 = __importDefault(require("glob"));
14
+ const utils_1 = require("./utils");
15
+ /**
16
+ * Scans a single package and its dependencies for license information
17
+ *
18
+ * @param packageName Name of the package to scan
19
+ * @param requiredVersion Version of the package to scan; this is the version specifier from package.json, e.g. `^1.0.0`, `~2.3.4`, etc.
20
+ * @param processedPackages Set of already processed packages (avoids cycles)
21
+ * @param result Aggregated licenses object to store the results; the keys will be in the format of `packageName@version` where version is the resolved version of the package
22
+ * @param scanOptionsFactory Factory function to create scan options for dependencies; defaults to {@link PackageUtils.legacyDefaultScanPackageOptionsFactory}
23
+ * @param isOptionalDependency Whether the package is an optional dependency, in which case a warning will not be logged if the corresponding package.json is not found; defaults to `false`
24
+ * @param parentPackageRoot Optional path to the parent package root, has priority over default root to lock for dependencies in; used to discover different versions of the same package installed in nested node_modules, e.g. suppose `X@1`, `Y@1` where `Y@1` -> `X@2`; then, node_modules would have `X@1`, `Y@1` and `X@2` would be installed to `node_modules/Y/node_modules/X@2`
25
+ */
26
+ function scanPackage(packageName, requiredVersion, processedPackages, result, scanOptionsFactory = utils_1.PackageUtils.legacyDefaultScanPackageOptionsFactory, { parentPackageRoot, parentPackageName, dependencyType, parentPackageRequiredVersion, parentPackageResolvedVersion, }) {
27
+ const requiredVersionPackageKey = `${packageName}@${requiredVersion}`;
28
+ // Skip if already processed to avoid circular dependencies
29
+ if (processedPackages.has(requiredVersionPackageKey)) {
30
+ return;
31
+ }
32
+ // If the package is a file: dependency, warn about lack of support
33
+ if (requiredVersion.startsWith('file:')) {
34
+ console.warn(`[react-native-legal] ${packageName} (${requiredVersion}) is 'file:' dependency. Such packages are not supported yet (see https://callstackincubator.github.io/react-native-legal/docs/programmatic-usage.html#known-limitations).`);
35
+ }
36
+ processedPackages.add(requiredVersionPackageKey);
37
+ try {
38
+ const localPackageJsonPath = utils_1.PackageUtils.getPackageJsonPath(packageName, parentPackageRoot);
39
+ if (!localPackageJsonPath) {
40
+ // do not warn if the package is an optional dependency, it's normal it may not be installed
41
+ if (!dependencyType.toLowerCase().includes('optional')) {
42
+ console.warn(`[react-native-legal] skipping ${requiredVersionPackageKey} could not find package.json`);
43
+ }
44
+ return;
45
+ }
46
+ const localPackageJson = require(path_1.default.resolve(localPackageJsonPath));
47
+ if (localPackageJson.private !== true) {
48
+ const licenseFiles = glob_1.default.sync('LICEN{S,C}E{.md,}', {
49
+ cwd: path_1.default.dirname(localPackageJsonPath),
50
+ absolute: true,
51
+ nocase: true,
52
+ nodir: true,
53
+ ignore: '**/{__tests__,__fixtures__,__mocks__}/**',
54
+ });
55
+ const resolvedVersionPackageKey = `${packageName}@${localPackageJson.version}`;
56
+ result[resolvedVersionPackageKey] = {
57
+ name: packageName,
58
+ author: utils_1.PackageUtils.parseAuthorField(localPackageJson),
59
+ content: licenseFiles?.[0] ? fs_1.default.readFileSync(licenseFiles[0], { encoding: 'utf-8' }) : undefined,
60
+ file: licenseFiles?.[0] ? licenseFiles[0] : undefined,
61
+ description: localPackageJson.description,
62
+ type: utils_1.PackageUtils.parseLicenseField(localPackageJson),
63
+ url: utils_1.PackageUtils.parseRepositoryFieldToUrl(localPackageJson),
64
+ version: localPackageJson.version,
65
+ requiredVersion,
66
+ parentPackageName,
67
+ parentPackageRequiredVersion,
68
+ parentPackageResolvedVersion,
69
+ dependencyType,
70
+ };
71
+ }
72
+ const dependencies = localPackageJson.dependencies;
73
+ const devDependencies = localPackageJson.devDependencies;
74
+ const optionalDependencies = localPackageJson.optionalDependencies;
75
+ const isWorkspacePackage = requiredVersion.startsWith('workspace:');
76
+ const scanOptions = scanOptionsFactory({
77
+ isRoot: false,
78
+ isWorkspacePackage,
79
+ });
80
+ // check if transitive dependencies should be scanned
81
+ if (!scanOptions.includeTransitiveDependencies) {
82
+ return;
83
+ }
84
+ // helper used for finding nested dependencies installed with different versions for a given package, see docstring of scanPackage
85
+ const currentPackageRoot = path_1.default.dirname(localPackageJsonPath);
86
+ for (const { dependencyType, packages } of [
87
+ {
88
+ dependencyType: 'transitiveDependency',
89
+ packages: dependencies ? Object.entries(dependencies) : [],
90
+ },
91
+ {
92
+ dependencyType: 'transitiveDevDependency',
93
+ packages: devDependencies && scanOptions.includeDevDependencies ? Object.entries(devDependencies) : [],
94
+ },
95
+ {
96
+ dependencyType: 'transitiveOptionalDependency',
97
+ packages: optionalDependencies && scanOptions.includeOptionalDependencies ? Object.entries(optionalDependencies) : [],
98
+ },
99
+ ]) {
100
+ for (const [depName, depVersion] of packages) {
101
+ scanPackage(depName, depVersion, processedPackages, result, scanOptionsFactory, {
102
+ dependencyType,
103
+ parentPackageRoot: currentPackageRoot,
104
+ parentPackageName: packageName,
105
+ parentPackageRequiredVersion: requiredVersion,
106
+ parentPackageResolvedVersion: localPackageJson.version,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ catch (error) {
112
+ console.warn(`[react-native-legal] could not process package.json for ${packageName}`);
113
+ }
114
+ }
115
+ /**
116
+ * Scans `package.json` and searches for all packages under `dependencies` field. Supports monorepo projects.
117
+ *
118
+ * @param appPackageJsonPath Path to the `package.json` file of the application
119
+ * @param scanOptionsFactory Factory function to create scan options for dependencies; defaults to {@link PackageUtils.legacyDefaultScanPackageOptionsFactory}
120
+ * @returns Aggregated licenses object containing all scanned dependencies and their license information
121
+ */
122
+ function scanDependencies(appPackageJsonPath, scanOptionsFactory = utils_1.PackageUtils.legacyDefaultScanPackageOptionsFactory) {
123
+ const appPackageJson = require(path_1.default.resolve(appPackageJsonPath));
124
+ const dependencies = appPackageJson.dependencies;
125
+ const devDependencies = appPackageJson.devDependencies;
126
+ const optionalDependencies = appPackageJson.optionalDependencies;
127
+ const result = {};
128
+ const processedPackages = new Set();
129
+ const rootScanOptions = scanOptionsFactory({ isRoot: true, isWorkspacePackage: false });
130
+ for (const { dependencyType, packages } of [
131
+ {
132
+ dependencyType: 'dependency',
133
+ packages: dependencies ? Object.entries(dependencies) : [],
134
+ },
135
+ {
136
+ dependencyType: 'devDependency',
137
+ packages: devDependencies && rootScanOptions.includeDevDependencies ? Object.entries(devDependencies) : [],
138
+ },
139
+ {
140
+ dependencyType: 'optionalDependency',
141
+ packages: optionalDependencies && rootScanOptions.includeOptionalDependencies ? Object.entries(optionalDependencies) : [],
142
+ },
143
+ ]) {
144
+ for (const [depName, depVersion] of packages) {
145
+ scanPackage(depName, depVersion, processedPackages, result, scanOptionsFactory, {
146
+ dependencyType,
147
+ });
148
+ }
149
+ }
150
+ return result;
151
+ }
152
+ /**
153
+ * Generates LicensePlist-compatible metadata for NPM dependencies as a YAML string.
154
+ *
155
+ * To write a file directly, use `writeLicensePlistNPMOutput` function.
156
+ *
157
+ * @param licenses Scanned NPM licenses
158
+ * @param iosProjectPath Path to the iOS project directory
159
+ * @see {@link writeLicensePlistNPMOutput}
160
+ */
161
+ function generateLicensePlistNPMOutput(licenses, iosProjectPath) {
162
+ const renames = {};
163
+ const licenseEntries = Object.entries(licenses).map(([packageKey, licenseObj]) => {
164
+ const normalizedPackageNameWithVersion = utils_1.PackageUtils.normalizePackageName(packageKey);
165
+ if (licenseObj.name !== normalizedPackageNameWithVersion) {
166
+ renames[normalizedPackageNameWithVersion] = licenseObj.name;
167
+ }
168
+ const relativeLicenseFile = licenseObj.file ? path_1.default.relative(iosProjectPath, licenseObj.file) : undefined;
169
+ return {
170
+ name: normalizedPackageNameWithVersion,
171
+ version: licenseObj.version,
172
+ ...(licenseObj.url && { source: licenseObj.url }),
173
+ ...(licenseObj.file
174
+ ? { file: relativeLicenseFile }
175
+ : { body: licenseObj.content ?? licenseObj.type ?? 'UNKNOWN' }),
176
+ };
177
+ });
178
+ const yamlDoc = {
179
+ ...(Object.keys(renames).length > 0 && { rename: renames }),
180
+ manual: licenseEntries,
181
+ };
182
+ const yamlContent = [
183
+ '# BEGIN Generated NPM license entries',
184
+ utils_1.YamlUtils.toYaml(yamlDoc),
185
+ '# END Generated NPM license entries',
186
+ ].join('\n');
187
+ return yamlContent;
188
+ }
189
+ /**
190
+ * Writes LicensePlist-compatible metadata for NPM dependencies to a file
191
+ *
192
+ * This will take scanned NPM licenses and produce following output inside iOS project's directory:
193
+ *
194
+ * ```
195
+ * | - ios
196
+ * | ---- myawesomeapp
197
+ * | ---- myawesomeapp.xcodeproj
198
+ * | ---- myawesomeapp.xcodeworkspace
199
+ * | ---- license_plist.yml <--- generated LicensePlist config with NPM dependencies
200
+ * | ---- Podfile
201
+ * | ---- Podfile.lock
202
+ * ```
203
+ *
204
+ * @param licenses Scanned NPM licenses
205
+ * @param iosProjectPath Path to the iOS project directory
206
+ * @param plistLikeOutput Optional pre-generated string output to use instead of generating it using `generateLicensePlistNPMOutput`
207
+ * @see {@link generateLicensePlistNPMOutput}
208
+ */
209
+ function writeLicensePlistNPMOutput(licenses, iosProjectPath, plistLikeOutput) {
210
+ if (!plistLikeOutput) {
211
+ plistLikeOutput = generateLicensePlistNPMOutput(licenses, iosProjectPath);
212
+ }
213
+ fs_1.default.writeFileSync(path_1.default.join(iosProjectPath, 'license_plist.yml'), plistLikeOutput, { encoding: 'utf-8' });
214
+ }
215
+ /**
216
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
217
+ *
218
+ * This will take scanned NPM licenses and produce output that can be modified and/or written to the Android project files.
219
+ *
220
+ * @param licenses Scanned NPM licenses
221
+ * @returns Array of AboutLibrariesLikePackage objects, each representing a NPM dependency
222
+ * @see {@link writeAboutLibrariesNPMOutput}
223
+ */
224
+ function generateAboutLibrariesNPMOutput(licenses) {
225
+ return Object.entries(licenses)
226
+ .map(([packageKey, licenseObj]) => {
227
+ return {
228
+ artifactVersion: licenseObj.version,
229
+ content: licenseObj.content ?? '',
230
+ description: licenseObj.description ?? '',
231
+ developers: [{ name: licenseObj.author ?? '', organisationUrl: '' }],
232
+ licenses: [utils_1.PackageUtils.prepareAboutLibrariesLicenseField(licenseObj)],
233
+ name: licenseObj.name,
234
+ tag: '',
235
+ type: licenseObj.type,
236
+ uniqueId: utils_1.PackageUtils.normalizePackageName(packageKey),
237
+ website: licenseObj.url,
238
+ };
239
+ })
240
+ .map((jsonPayload) => {
241
+ const libraryJsonPayload = {
242
+ artifactVersion: jsonPayload.artifactVersion,
243
+ description: jsonPayload.description,
244
+ developers: jsonPayload.developers,
245
+ licenses: jsonPayload.licenses,
246
+ name: jsonPayload.name,
247
+ tag: jsonPayload.tag,
248
+ uniqueId: jsonPayload.uniqueId,
249
+ website: jsonPayload.website,
250
+ };
251
+ const licenseJsonPayload = {
252
+ content: jsonPayload.content,
253
+ hash: jsonPayload.licenses[0],
254
+ name: jsonPayload.type ?? '',
255
+ url: '',
256
+ };
257
+ return {
258
+ normalizedPackageNameWithVersion: jsonPayload.uniqueId,
259
+ libraryJsonPayload,
260
+ licenseJsonPayload,
261
+ };
262
+ });
263
+ }
264
+ /**
265
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
266
+ *
267
+ * This will take scanned NPM licenses and produce following output inside android project's directory:
268
+ *
269
+ * ```
270
+ * | - android
271
+ * | ---- app
272
+ * | ---- config <--- generated AboutLibraries config directory
273
+ * | ------- libraries <--- generated directory with JSON files list of NPM dependencies
274
+ * | ------- licenses <--- generated directory with JSON files list of used licenses
275
+ * | ---- build.gradle
276
+ * | ---- settings.gradle
277
+ * ```
278
+ *
279
+ * @param licenses Scanned NPM licenses
280
+ * @param androidProjectPath Path to the Android project directory
281
+ * @param aboutLibrariesLikeOutput Optional pre-generated output to use instead of generating it using `generateAboutLibrariesNPMOutput`
282
+ * @see {@link generateAboutLibrariesNPMOutput}
283
+ */
284
+ function writeAboutLibrariesNPMOutput(licenses, androidProjectPath, aboutLibrariesLikeOutput) {
285
+ const aboutLibrariesConfigDirPath = path_1.default.join(androidProjectPath, 'config');
286
+ const aboutLibrariesConfigLibrariesDirPath = path_1.default.join(aboutLibrariesConfigDirPath, 'libraries');
287
+ const aboutLibrariesConfigLicensesDirPath = path_1.default.join(aboutLibrariesConfigDirPath, 'licenses');
288
+ if (!fs_1.default.existsSync(aboutLibrariesConfigDirPath)) {
289
+ fs_1.default.mkdirSync(aboutLibrariesConfigDirPath);
290
+ }
291
+ if (!fs_1.default.existsSync(aboutLibrariesConfigLibrariesDirPath)) {
292
+ fs_1.default.mkdirSync(aboutLibrariesConfigLibrariesDirPath);
293
+ }
294
+ if (!fs_1.default.existsSync(aboutLibrariesConfigLicensesDirPath)) {
295
+ fs_1.default.mkdirSync(aboutLibrariesConfigLicensesDirPath);
296
+ }
297
+ if (!aboutLibrariesLikeOutput) {
298
+ aboutLibrariesLikeOutput = generateAboutLibrariesNPMOutput(licenses);
299
+ }
300
+ aboutLibrariesLikeOutput.forEach(({ normalizedPackageNameWithVersion, libraryJsonPayload, licenseJsonPayload }) => {
301
+ const libraryJsonFilePath = path_1.default.join(aboutLibrariesConfigLibrariesDirPath, `${normalizedPackageNameWithVersion}.json`);
302
+ const licenseJsonFilePath = path_1.default.join(aboutLibrariesConfigLicensesDirPath, `${licenseJsonPayload.hash}.json`);
303
+ fs_1.default.writeFileSync(libraryJsonFilePath, JSON.stringify(libraryJsonPayload));
304
+ if (!fs_1.default.existsSync(licenseJsonFilePath)) {
305
+ fs_1.default.writeFileSync(licenseJsonFilePath, JSON.stringify(licenseJsonPayload));
306
+ }
307
+ });
308
+ }
@@ -0,0 +1,3 @@
1
+ export * from './common';
2
+ export * as Types from './types';
3
+ export * from './utils';
package/build/index.js ADDED
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Types = void 0;
40
+ __exportStar(require("./common"), exports);
41
+ exports.Types = __importStar(require("./types"));
42
+ __exportStar(require("./utils"), exports);
@@ -0,0 +1,13 @@
1
+ export type AboutLibrariesLibraryJsonPayload = {
2
+ artifactVersion: string;
3
+ description: string;
4
+ developers: {
5
+ name: string;
6
+ organisationUrl: string;
7
+ }[];
8
+ licenses: string[];
9
+ name: string;
10
+ tag: string;
11
+ uniqueId: string;
12
+ website: string | undefined;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ export type AboutLibrariesLicenseJsonPayload = {
2
+ content: string;
3
+ hash: string;
4
+ name: string;
5
+ url: string;
6
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ import type { AboutLibrariesLibraryJsonPayload } from './AboutLibrariesLibraryJsonPayload';
2
+ import type { AboutLibrariesLicenseJsonPayload } from './AboutLibrariesLicenseJsonPayload';
3
+ export type AboutLibrariesLikePackageInfo = {
4
+ normalizedPackageNameWithVersion: string;
5
+ libraryJsonPayload: AboutLibrariesLibraryJsonPayload;
6
+ licenseJsonPayload: AboutLibrariesLicenseJsonPayload;
7
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import type { LicenseObj } from './LicenseObj';
2
+ /**
3
+ * Mapping from package keys in format `<package-name>/<package-version>` to license objects.
4
+ * @see {@link LicenseObj}
5
+ */
6
+ export type AggregatedLicensesObj = Record<string, LicenseObj>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ type BaseDependencyType = 'dependency' | 'devDependency' | 'optionalDependency' | 'peerDependency';
2
+ export type DependencyType = BaseDependencyType | `transitive${Capitalize<BaseDependencyType>}`;
3
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ import type { DependencyType } from './DependencyType';
2
+ import type { ScanPackageCallContext } from './ScanPackageCallContext';
3
+ export type LicenseObj = {
4
+ /** Package name */
5
+ name: string;
6
+ /** Package author */
7
+ author?: string;
8
+ /** Package license contents */
9
+ content?: string;
10
+ /** Package description */
11
+ description?: string;
12
+ /** License file path */
13
+ file?: string;
14
+ /** License type */
15
+ type?: string;
16
+ /** Package repository URL */
17
+ url?: string;
18
+ /** The resolved version that was actually installed */
19
+ version: string;
20
+ /** The source of how this package has been introduced to the dependency tree */
21
+ dependencyType: DependencyType;
22
+ /** The required version specified in package.json */
23
+ requiredVersion: string;
24
+ } & Pick<ScanPackageCallContext, 'parentPackageName' | 'parentPackageRequiredVersion' | 'parentPackageResolvedVersion'>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ export type LicensePlistPayload = {
2
+ name: string;
3
+ source?: string;
4
+ version: string;
5
+ body?: string;
6
+ file?: string;
7
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,25 @@
1
+ import type { DependencyType } from './DependencyType';
2
+ export type ScanPackageCallContext = {
3
+ /** Information on what is the source of the dependency on the package to be scanned */
4
+ dependencyType: DependencyType;
5
+ /**
6
+ * The name of the package that introduced the package to be scanned as a dependency (of any type);
7
+ * undefined if the package to be scanned is a dependency of the root package
8
+ */
9
+ parentPackageName?: string;
10
+ /**
11
+ * The installation directory of the package that introduced the package to be scanned as a dependency (of any type);
12
+ * undefined if the package to be scanned is a dependency of the root package
13
+ */
14
+ parentPackageRoot?: string;
15
+ /**
16
+ * The required version, as specified in package.json
17
+ * of the package that introduced the package to be scanned as a dependency (of any type)
18
+ */
19
+ parentPackageRequiredVersion?: string;
20
+ /**
21
+ * The resolved (actually installed by the package manager) version
22
+ * of the package that introduced the package to be scanned as a dependency (of any type)
23
+ */
24
+ parentPackageResolvedVersion?: string;
25
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });