@callstack/licenses 0.2.2 → 0.3.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.
- package/README.md +1 -1
- package/build/constants/index.d.ts +1 -0
- package/build/constants/index.js +17 -0
- package/build/constants/licenses.d.ts +7 -0
- package/build/constants/licenses.js +53 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +5 -4
- package/build/licenses/LicenseCategory.d.ts +6 -0
- package/build/licenses/LicenseCategory.js +10 -0
- package/build/licenses/descriptions.d.ts +16 -0
- package/build/licenses/descriptions.js +53 -0
- package/build/licenses/index.d.ts +3 -0
- package/build/licenses/index.js +19 -0
- package/build/licenses/licenseAnalysis.d.ts +15 -0
- package/build/licenses/licenseAnalysis.js +65 -0
- package/build/{common.d.ts → node/common.d.ts} +6 -6
- package/build/{common.js → node/common.js} +108 -60
- package/build/node/index.d.ts +3 -0
- package/build/node/index.js +19 -0
- package/build/node/utils/index.d.ts +2 -0
- package/build/node/utils/index.js +38 -0
- package/build/{utils → node/utils}/packageUtils.d.ts +2 -2
- package/build/{utils → node/utils}/packageUtils.js +1 -1
- package/build/types/AggregatedLicensesMapping.d.ts +6 -0
- package/build/types/{LicenseObj.d.ts → License.d.ts} +8 -2
- package/build/types/LicenseAnalysisResult.d.ts +5 -0
- package/build/types/LicenseAnalysisResult.js +2 -0
- package/build/types/LicenseStats.d.ts +28 -0
- package/build/types/LicenseStats.js +2 -0
- package/build/types/ParentPackageInfo.d.ts +14 -0
- package/build/types/ParentPackageInfo.js +2 -0
- package/build/types/index.d.ts +5 -2
- package/build/types/index.js +5 -2
- package/build/utils/index.d.ts +0 -2
- package/build/utils/index.js +1 -3
- package/package.json +20 -7
- package/src/constants/index.ts +1 -0
- package/src/constants/licenses.ts +58 -0
- package/src/index.ts +2 -1
- package/src/licenses/LicenseCategory.ts +6 -0
- package/src/licenses/descriptions.ts +56 -0
- package/src/licenses/index.ts +3 -0
- package/src/licenses/licenseAnalysis.ts +78 -0
- package/src/{common.ts → node/common.ts} +104 -45
- package/src/node/index.ts +3 -0
- package/src/node/utils/index.ts +2 -0
- package/src/{utils → node/utils}/packageUtils.ts +3 -3
- package/src/types/AggregatedLicensesMapping.ts +7 -0
- package/src/types/{LicenseObj.ts → License.ts} +9 -2
- package/src/types/LicenseAnalysisResult.ts +7 -0
- package/src/types/LicenseStats.ts +33 -0
- package/src/types/ParentPackageInfo.ts +16 -0
- package/src/types/index.ts +5 -2
- package/src/utils/index.ts +0 -2
- package/build/types/AggregatedLicensesObj.d.ts +0 -6
- package/src/types/AggregatedLicensesObj.ts +0 -7
- /package/build/{utils → node/utils}/miscUtils.d.ts +0 -0
- /package/build/{utils → node/utils}/miscUtils.js +0 -0
- /package/build/types/{AggregatedLicensesObj.js → AggregatedLicensesMapping.js} +0 -0
- /package/build/types/{LicenseObj.js → License.js} +0 -0
- /package/src/{utils → node/utils}/miscUtils.ts +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
import glob from 'glob';
|
|
5
5
|
|
|
@@ -7,13 +7,16 @@ import type {
|
|
|
7
7
|
AboutLibrariesLibraryJsonPayload,
|
|
8
8
|
AboutLibrariesLicenseJsonPayload,
|
|
9
9
|
AboutLibrariesLikePackageInfo,
|
|
10
|
-
|
|
10
|
+
AggregatedLicensesMapping,
|
|
11
11
|
DependencyType,
|
|
12
12
|
LicensePlistPayload,
|
|
13
|
+
ParentPackageInfo,
|
|
13
14
|
ScanPackageCallContext,
|
|
14
15
|
ScanPackageOptionsFactory,
|
|
15
|
-
} from '
|
|
16
|
-
import {
|
|
16
|
+
} from '../types';
|
|
17
|
+
import { YamlUtils } from '../utils';
|
|
18
|
+
|
|
19
|
+
import { PackageUtils } from './utils';
|
|
17
20
|
|
|
18
21
|
type InternalScanGroupSpecifier = { packages: [depName: string, depVersion: string][]; dependencyType: DependencyType };
|
|
19
22
|
|
|
@@ -32,7 +35,7 @@ function scanPackage(
|
|
|
32
35
|
packageName: string,
|
|
33
36
|
requiredVersion: string,
|
|
34
37
|
processedPackages: Set<string>,
|
|
35
|
-
result:
|
|
38
|
+
result: AggregatedLicensesMapping,
|
|
36
39
|
scanOptionsFactory: ScanPackageOptionsFactory = PackageUtils.legacyDefaultScanPackageOptionsFactory,
|
|
37
40
|
{
|
|
38
41
|
parentPackageRoot,
|
|
@@ -83,21 +86,37 @@ function scanPackage(
|
|
|
83
86
|
|
|
84
87
|
const resolvedVersionPackageKey = `${packageName}@${localPackageJson.version}`;
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
89
|
+
let parentPackageInfo: ParentPackageInfo | undefined;
|
|
90
|
+
if (parentPackageName && parentPackageRequiredVersion && parentPackageResolvedVersion) {
|
|
91
|
+
parentPackageInfo = {
|
|
92
|
+
name: parentPackageName,
|
|
93
|
+
requiredVersion: parentPackageRequiredVersion,
|
|
94
|
+
resolvedVersion: parentPackageResolvedVersion,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (parentPackageInfo && resolvedVersionPackageKey in result) {
|
|
99
|
+
result[resolvedVersionPackageKey].parentPackages = [
|
|
100
|
+
...(result[resolvedVersionPackageKey].parentPackages ?? []),
|
|
101
|
+
parentPackageInfo,
|
|
102
|
+
];
|
|
103
|
+
} else {
|
|
104
|
+
result[resolvedVersionPackageKey] = {
|
|
105
|
+
name: packageName,
|
|
106
|
+
author: PackageUtils.parseAuthorField(localPackageJson),
|
|
107
|
+
content: licenseFiles?.[0] ? fs.readFileSync(licenseFiles[0], { encoding: 'utf-8' }) : undefined,
|
|
108
|
+
file: licenseFiles?.[0] ? licenseFiles[0] : undefined,
|
|
109
|
+
description: localPackageJson.description,
|
|
110
|
+
type: PackageUtils.parseLicenseField(localPackageJson),
|
|
111
|
+
url: PackageUtils.parseRepositoryFieldToUrl(localPackageJson),
|
|
112
|
+
version: localPackageJson.version,
|
|
113
|
+
requiredVersion,
|
|
114
|
+
parentPackages: parentPackageInfo ? [parentPackageInfo] : [],
|
|
115
|
+
parentPackageRequiredVersion,
|
|
116
|
+
parentPackageResolvedVersion,
|
|
117
|
+
dependencyType,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
101
120
|
}
|
|
102
121
|
|
|
103
122
|
const dependencies: MaybeDependencyMapping = localPackageJson.dependencies;
|
|
@@ -161,12 +180,12 @@ type MaybeDependencyMapping = DependencyMapping | undefined;
|
|
|
161
180
|
export function scanDependencies(
|
|
162
181
|
appPackageJsonPath: string,
|
|
163
182
|
scanOptionsFactory: ScanPackageOptionsFactory = PackageUtils.legacyDefaultScanPackageOptionsFactory,
|
|
164
|
-
):
|
|
183
|
+
): AggregatedLicensesMapping {
|
|
165
184
|
const appPackageJson = require(path.resolve(appPackageJsonPath));
|
|
166
185
|
const dependencies: MaybeDependencyMapping = appPackageJson.dependencies;
|
|
167
186
|
const devDependencies: MaybeDependencyMapping = appPackageJson.devDependencies;
|
|
168
187
|
const optionalDependencies: MaybeDependencyMapping = appPackageJson.optionalDependencies;
|
|
169
|
-
const result:
|
|
188
|
+
const result: AggregatedLicensesMapping = {};
|
|
170
189
|
const processedPackages = new Set<string>();
|
|
171
190
|
|
|
172
191
|
const rootScanOptions = scanOptionsFactory({ isRoot: true, isWorkspacePackage: false });
|
|
@@ -196,6 +215,9 @@ export function scanDependencies(
|
|
|
196
215
|
return result;
|
|
197
216
|
}
|
|
198
217
|
|
|
218
|
+
const PODSPEC_NAME_REGEX =
|
|
219
|
+
/(Pod::Spec\.new\s+do\s+\|(?<specref>.*)\|).*(\k<specref>\.name\s+=\s+(?<quote>["'])(?<specname>[a-zA-Z0-9_\-@]+)\k<quote>)/;
|
|
220
|
+
|
|
199
221
|
/**
|
|
200
222
|
* Generates LicensePlist-compatible metadata for NPM dependencies as a YAML string.
|
|
201
223
|
*
|
|
@@ -205,30 +227,67 @@ export function scanDependencies(
|
|
|
205
227
|
* @param iosProjectPath Path to the iOS project directory
|
|
206
228
|
* @see {@link writeLicensePlistNPMOutput}
|
|
207
229
|
*/
|
|
208
|
-
export function generateLicensePlistNPMOutput(licenses:
|
|
230
|
+
export function generateLicensePlistNPMOutput(licenses: AggregatedLicensesMapping, iosProjectPath: string): string {
|
|
209
231
|
const renames: Record<string, string> = {};
|
|
210
|
-
const licenseEntries = Object.entries(licenses).map(([packageKey,
|
|
232
|
+
const licenseEntries = Object.entries(licenses).map(([packageKey, license]) => {
|
|
211
233
|
const normalizedPackageNameWithVersion = PackageUtils.normalizePackageName(packageKey);
|
|
212
234
|
|
|
213
|
-
if (
|
|
214
|
-
renames[normalizedPackageNameWithVersion] =
|
|
235
|
+
if (license.name !== normalizedPackageNameWithVersion) {
|
|
236
|
+
renames[normalizedPackageNameWithVersion] = license.name;
|
|
215
237
|
}
|
|
216
238
|
|
|
217
|
-
const relativeLicenseFile =
|
|
239
|
+
const relativeLicenseFile = license.file ? path.relative(iosProjectPath, license.file) : undefined;
|
|
218
240
|
|
|
219
241
|
return {
|
|
220
242
|
name: normalizedPackageNameWithVersion,
|
|
221
|
-
version:
|
|
222
|
-
...(
|
|
223
|
-
...(
|
|
224
|
-
? { file: relativeLicenseFile }
|
|
225
|
-
: { body: licenseObj.content ?? licenseObj.type ?? 'UNKNOWN' }),
|
|
243
|
+
version: license.version,
|
|
244
|
+
...(license.url && { source: license.url }),
|
|
245
|
+
...(license.file ? { file: relativeLicenseFile } : { body: license.content ?? license.type ?? 'UNKNOWN' }),
|
|
226
246
|
} as LicensePlistPayload;
|
|
227
247
|
});
|
|
228
248
|
|
|
249
|
+
const excludedEntries = Object.values(licenses).reduce<Array<{ name: string }>>((acc, license) => {
|
|
250
|
+
const packageName = license.name;
|
|
251
|
+
const localPackageJsonPath = PackageUtils.getPackageJsonPath(packageName);
|
|
252
|
+
|
|
253
|
+
if (!localPackageJsonPath) {
|
|
254
|
+
return acc;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const podspecFiles = glob.sync('**.podspec', {
|
|
258
|
+
cwd: path.dirname(localPackageJsonPath),
|
|
259
|
+
absolute: true,
|
|
260
|
+
nocase: true,
|
|
261
|
+
nodir: true,
|
|
262
|
+
ignore: '**/{__tests__,__fixtures__,__mocks__}/**',
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (!podspecFiles) {
|
|
266
|
+
return acc;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const podspecEntries = podspecFiles.map((podspecFile) => {
|
|
270
|
+
const podspecContent = fs.readFileSync(podspecFile, { encoding: 'utf-8' });
|
|
271
|
+
const podspecContentShrinked = podspecContent.replace(/\n/g, ' ');
|
|
272
|
+
const { specname } = PODSPEC_NAME_REGEX.exec(podspecContentShrinked)?.groups ?? {};
|
|
273
|
+
|
|
274
|
+
return { name: specname ?? packageName };
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
return [...acc, ...podspecEntries];
|
|
278
|
+
}, []);
|
|
279
|
+
|
|
229
280
|
const yamlDoc = {
|
|
230
281
|
...(Object.keys(renames).length > 0 && { rename: renames }),
|
|
231
282
|
manual: licenseEntries,
|
|
283
|
+
/**
|
|
284
|
+
* Adding excludes to prevent duplicates - NPM packages with iOS Podspecs are already
|
|
285
|
+
* manually included in the `licenseEntries`. However License Plist is automatically including all
|
|
286
|
+
* the entries detected via Pods-<project-name>-acknowledgements.plist, which also
|
|
287
|
+
* includes the NPM package with iOS Podspecs - let's filter them out,
|
|
288
|
+
* so that only the manual NPM entries are displayed
|
|
289
|
+
*/
|
|
290
|
+
exclude: excludedEntries,
|
|
232
291
|
};
|
|
233
292
|
|
|
234
293
|
const yamlContent = [
|
|
@@ -261,7 +320,7 @@ export function generateLicensePlistNPMOutput(licenses: AggregatedLicensesObj, i
|
|
|
261
320
|
* @see {@link generateLicensePlistNPMOutput}
|
|
262
321
|
*/
|
|
263
322
|
export function writeLicensePlistNPMOutput(
|
|
264
|
-
licenses:
|
|
323
|
+
licenses: AggregatedLicensesMapping,
|
|
265
324
|
iosProjectPath: string,
|
|
266
325
|
plistLikeOutput?: string,
|
|
267
326
|
) {
|
|
@@ -281,20 +340,20 @@ export function writeLicensePlistNPMOutput(
|
|
|
281
340
|
* @returns Array of AboutLibrariesLikePackage objects, each representing a NPM dependency
|
|
282
341
|
* @see {@link writeAboutLibrariesNPMOutput}
|
|
283
342
|
*/
|
|
284
|
-
export function generateAboutLibrariesNPMOutput(licenses:
|
|
343
|
+
export function generateAboutLibrariesNPMOutput(licenses: AggregatedLicensesMapping): AboutLibrariesLikePackageInfo[] {
|
|
285
344
|
return Object.entries(licenses)
|
|
286
|
-
.map(([packageKey,
|
|
345
|
+
.map(([packageKey, license]) => {
|
|
287
346
|
return {
|
|
288
|
-
artifactVersion:
|
|
289
|
-
content:
|
|
290
|
-
description:
|
|
291
|
-
developers: [{ name:
|
|
292
|
-
licenses: [PackageUtils.prepareAboutLibrariesLicenseField(
|
|
293
|
-
name:
|
|
347
|
+
artifactVersion: license.version,
|
|
348
|
+
content: license.content ?? '',
|
|
349
|
+
description: license.description ?? '',
|
|
350
|
+
developers: [{ name: license.author ?? '', organisationUrl: '' }],
|
|
351
|
+
licenses: [PackageUtils.prepareAboutLibrariesLicenseField(license)],
|
|
352
|
+
name: license.name,
|
|
294
353
|
tag: '',
|
|
295
|
-
type:
|
|
354
|
+
type: license.type,
|
|
296
355
|
uniqueId: PackageUtils.normalizePackageName(packageKey),
|
|
297
|
-
website:
|
|
356
|
+
website: license.url,
|
|
298
357
|
};
|
|
299
358
|
})
|
|
300
359
|
.map((jsonPayload) => {
|
|
@@ -344,7 +403,7 @@ export function generateAboutLibrariesNPMOutput(licenses: AggregatedLicensesObj)
|
|
|
344
403
|
* @see {@link generateAboutLibrariesNPMOutput}
|
|
345
404
|
*/
|
|
346
405
|
export function writeAboutLibrariesNPMOutput(
|
|
347
|
-
licenses:
|
|
406
|
+
licenses: AggregatedLicensesMapping,
|
|
348
407
|
androidProjectPath: string,
|
|
349
408
|
aboutLibrariesLikeOutput?: AboutLibrariesLikePackageInfo[],
|
|
350
409
|
) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
import type {
|
|
4
|
+
import type { License, ScanPackageOptionsFactory } from '../../types';
|
|
5
|
+
import { normalizeRepositoryUrl } from '../../utils/repositoryUtils';
|
|
5
6
|
|
|
6
7
|
import { sha512 } from './miscUtils';
|
|
7
|
-
import { normalizeRepositoryUrl } from './repositoryUtils';
|
|
8
8
|
|
|
9
9
|
export function getPackageJsonPath(dependency: string, root?: string) {
|
|
10
10
|
const rootsToSearch = [
|
|
@@ -54,7 +54,7 @@ export function normalizePackageName(packageName: string): string {
|
|
|
54
54
|
return packageName.replace('/', '_');
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function prepareAboutLibrariesLicenseField(license:
|
|
57
|
+
export function prepareAboutLibrariesLicenseField(license: License) {
|
|
58
58
|
if (!license.type) {
|
|
59
59
|
return '';
|
|
60
60
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { DependencyType } from './DependencyType';
|
|
2
|
+
import type { ParentPackageInfo } from './ParentPackageInfo';
|
|
2
3
|
import type { ScanPackageCallContext } from './ScanPackageCallContext';
|
|
3
4
|
|
|
4
|
-
export type
|
|
5
|
+
export type License = {
|
|
5
6
|
/** Package name */
|
|
6
7
|
name: string;
|
|
7
8
|
|
|
@@ -31,4 +32,10 @@ export type LicenseObj = {
|
|
|
31
32
|
|
|
32
33
|
/** The required version specified in package.json */
|
|
33
34
|
requiredVersion: string;
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The name(s) of the package(s) that introduced the package as a dependency (of any type);
|
|
38
|
+
* empty array if the package is a dependency of the root package
|
|
39
|
+
*/
|
|
40
|
+
parentPackages: ParentPackageInfo[];
|
|
41
|
+
} & Pick<ScanPackageCallContext, 'parentPackageRequiredVersion' | 'parentPackageResolvedVersion'>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LicenseCategory } from '../licenses/LicenseCategory';
|
|
2
|
+
|
|
3
|
+
export interface LicenseStats {
|
|
4
|
+
/**
|
|
5
|
+
* Total number of packages
|
|
6
|
+
*/
|
|
7
|
+
total: number;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Mapping of license category to count of packages in that category
|
|
11
|
+
*/
|
|
12
|
+
byCategory: Record<LicenseCategory, number>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Mapping of license name to count of packages with that license
|
|
16
|
+
*/
|
|
17
|
+
byLicense: Record<string, number>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Information about the presence of different license categories
|
|
21
|
+
*/
|
|
22
|
+
categoriesPresence: {
|
|
23
|
+
hasAnyUnknown: boolean;
|
|
24
|
+
hasAnyWeakCopyleft: boolean;
|
|
25
|
+
hasAnyStrongCopyleft: boolean;
|
|
26
|
+
hasAllPermissive: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Description of the graph state based on the license categories
|
|
31
|
+
*/
|
|
32
|
+
description: string;
|
|
33
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type ParentPackageInfo = {
|
|
2
|
+
/**
|
|
3
|
+
* The name of the package
|
|
4
|
+
*/
|
|
5
|
+
name: string;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The required version, as specified in package.json
|
|
9
|
+
*/
|
|
10
|
+
requiredVersion: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The resolved version, as specified in package.json
|
|
14
|
+
*/
|
|
15
|
+
resolvedVersion: string;
|
|
16
|
+
};
|
package/src/types/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
1
|
+
export * from './License';
|
|
2
|
+
export * from './AggregatedLicensesMapping';
|
|
3
3
|
export * from './AboutLibrariesLibraryJsonPayload';
|
|
4
4
|
export * from './AboutLibrariesLicenseJsonPayload';
|
|
5
5
|
export * from './LicensePlistPayload';
|
|
@@ -7,3 +7,6 @@ export * from './AboutLibrariesLikePackageInfo';
|
|
|
7
7
|
export * from './ScanPackageOptions';
|
|
8
8
|
export * from './ScanPackageCallContext';
|
|
9
9
|
export * from './DependencyType';
|
|
10
|
+
export * from './ParentPackageInfo';
|
|
11
|
+
export * from './LicenseAnalysisResult';
|
|
12
|
+
export * from './LicenseStats';
|
package/src/utils/index.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|