@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.
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/build/common.d.ts +71 -0
- package/build/common.js +308 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +42 -0
- package/build/types/AboutLibrariesLibraryJsonPayload.d.ts +13 -0
- package/build/types/AboutLibrariesLibraryJsonPayload.js +2 -0
- package/build/types/AboutLibrariesLicenseJsonPayload.d.ts +6 -0
- package/build/types/AboutLibrariesLicenseJsonPayload.js +2 -0
- package/build/types/AboutLibrariesLikePackageInfo.d.ts +7 -0
- package/build/types/AboutLibrariesLikePackageInfo.js +2 -0
- package/build/types/AggregatedLicensesObj.d.ts +6 -0
- package/build/types/AggregatedLicensesObj.js +2 -0
- package/build/types/DependencyType.d.ts +3 -0
- package/build/types/DependencyType.js +2 -0
- package/build/types/LicenseObj.d.ts +24 -0
- package/build/types/LicenseObj.js +2 -0
- package/build/types/LicensePlistPayload.d.ts +7 -0
- package/build/types/LicensePlistPayload.js +2 -0
- package/build/types/ScanPackageCallContext.d.ts +25 -0
- package/build/types/ScanPackageCallContext.js +2 -0
- package/build/types/ScanPackageOptions.d.ts +24 -0
- package/build/types/ScanPackageOptions.js +2 -0
- package/build/types/index.d.ts +9 -0
- package/build/types/index.js +25 -0
- package/build/utils/index.d.ts +4 -0
- package/build/utils/index.js +40 -0
- package/build/utils/miscUtils.d.ts +6 -0
- package/build/utils/miscUtils.js +39 -0
- package/build/utils/packageUtils.d.ts +26 -0
- package/build/utils/packageUtils.js +100 -0
- package/build/utils/repositoryUtils.d.ts +1 -0
- package/build/utils/repositoryUtils.js +18 -0
- package/build/utils/yamlUtils.d.ts +4 -0
- package/build/utils/yamlUtils.js +64 -0
- package/package.json +67 -0
- package/src/common.ts +384 -0
- package/src/index.ts +3 -0
- package/src/types/AboutLibrariesLibraryJsonPayload.ts +10 -0
- package/src/types/AboutLibrariesLicenseJsonPayload.ts +6 -0
- package/src/types/AboutLibrariesLikePackageInfo.ts +8 -0
- package/src/types/AggregatedLicensesObj.ts +7 -0
- package/src/types/DependencyType.ts +3 -0
- package/src/types/LicenseObj.ts +34 -0
- package/src/types/LicensePlistPayload.ts +7 -0
- package/src/types/ScanPackageCallContext.ts +30 -0
- package/src/types/ScanPackageOptions.ts +29 -0
- package/src/types/index.ts +9 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/miscUtils.ts +42 -0
- package/src/utils/packageUtils.ts +103 -0
- package/src/utils/repositoryUtils.ts +17 -0
- package/src/utils/yamlUtils.ts +73 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import type { LicenseObj, ScanPackageOptionsFactory } from '../types';
|
|
5
|
+
|
|
6
|
+
import { sha512 } from './miscUtils';
|
|
7
|
+
import { normalizeRepositoryUrl } from './repositoryUtils';
|
|
8
|
+
|
|
9
|
+
export function getPackageJsonPath(dependency: string, root?: string) {
|
|
10
|
+
const rootsToSearch = [
|
|
11
|
+
...(root ? [root] : []), // provided for purpose of nested node_modules resolution inside a package dir, in a subdirectory inside the root node_modules dir
|
|
12
|
+
process.cwd(), // fallback - root node_modules directory home
|
|
13
|
+
]; // in order of priority (left-to-right)
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
return require.resolve(`${dependency}/package.json`, { paths: rootsToSearch });
|
|
17
|
+
} catch (error) {
|
|
18
|
+
for (const root of rootsToSearch) {
|
|
19
|
+
const pkgJsonInNodeModules = path.join(root, 'node_modules', dependency, 'package.json');
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(pkgJsonInNodeModules)) {
|
|
22
|
+
return pkgJsonInNodeModules;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return resolvePackageJsonFromEntry(dependency); // final fallback
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolvePackageJsonFromEntry(dependency: string) {
|
|
31
|
+
try {
|
|
32
|
+
const entryPath = require.resolve(dependency);
|
|
33
|
+
const packageDir = findPackageRoot(entryPath);
|
|
34
|
+
|
|
35
|
+
if (!packageDir) return null;
|
|
36
|
+
|
|
37
|
+
const packageJsonPath = path.join(packageDir, 'package.json');
|
|
38
|
+
|
|
39
|
+
return fs.existsSync(packageJsonPath) ? packageJsonPath : null;
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function findPackageRoot(entryPath: string) {
|
|
46
|
+
let currentDir = path.dirname(entryPath);
|
|
47
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
48
|
+
if (fs.existsSync(path.join(currentDir, 'package.json'))) return currentDir;
|
|
49
|
+
currentDir = path.dirname(currentDir);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function normalizePackageName(packageName: string): string {
|
|
54
|
+
return packageName.replace('/', '_');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function prepareAboutLibrariesLicenseField(license: LicenseObj) {
|
|
58
|
+
if (!license.type) {
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return `${license.type}_${sha512(license.content ?? license.type)}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function parseAuthorField(json: { author: string | { name: string } }) {
|
|
66
|
+
if (typeof json.author === 'object' && typeof json.author.name === 'string') {
|
|
67
|
+
return json.author.name;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (typeof json.author === 'string') {
|
|
71
|
+
return json.author;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function parseLicenseField(json: { license: string | { type: string } }) {
|
|
76
|
+
if (typeof json.license === 'object' && typeof json.license.type === 'string') {
|
|
77
|
+
return json.license.type;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (typeof json.license === 'string') {
|
|
81
|
+
return json.license;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function parseRepositoryFieldToUrl(json: { repository: string | { url?: string } }) {
|
|
86
|
+
if (typeof json.repository === 'object' && typeof json.repository.url === 'string') {
|
|
87
|
+
return normalizeRepositoryUrl(json.repository.url);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof json.repository === 'string') {
|
|
91
|
+
return normalizeRepositoryUrl(json.repository);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Default value consistent with legacy behaviour assumptions for the scan package options factory
|
|
97
|
+
* used so as not to introduce breaking API changes to the shared package
|
|
98
|
+
*/
|
|
99
|
+
export const legacyDefaultScanPackageOptionsFactory: ScanPackageOptionsFactory = () => ({
|
|
100
|
+
includeTransitiveDependencies: true,
|
|
101
|
+
includeDevDependencies: false,
|
|
102
|
+
includeOptionalDependencies: true,
|
|
103
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function normalizeRepositoryUrl(url: string) {
|
|
2
|
+
return (
|
|
3
|
+
url
|
|
4
|
+
.replace('git+ssh://git@', 'git://')
|
|
5
|
+
.replace('.git', '')
|
|
6
|
+
.replace('git+https://github.com', 'https://github.com')
|
|
7
|
+
.replace('.git', '')
|
|
8
|
+
.replace('git://github.com', 'https://github.com')
|
|
9
|
+
.replace('.git', '')
|
|
10
|
+
.replace('git@github.com:', 'https://github.com/')
|
|
11
|
+
.replace('.git', '')
|
|
12
|
+
.replace('github:', 'https://github.com/')
|
|
13
|
+
.replace('.git', '')
|
|
14
|
+
// below: handling of edge case: git+ssh://git@github.com:X/Y.git -> https://github.com:X/Y
|
|
15
|
+
.replace('github.com:', 'github.com/')
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export function needsQuoting(value: string) {
|
|
2
|
+
return (
|
|
3
|
+
value === '' || // empty string
|
|
4
|
+
/^[#:>|-]/.test(value) || // starts with special char
|
|
5
|
+
/^['"{}[\],&*#?|<>=!%@`]/.test(value) || // starts with indicator chars
|
|
6
|
+
/^[\s]|[\s]$/.test(value) || // has leading/trailing whitespace
|
|
7
|
+
/^[\d.+-]/.test(value) || // looks like a number/bool/null
|
|
8
|
+
/[\n"'\\\s]/.test(value) || // contains newlines, quotes, backslash, or spaces
|
|
9
|
+
/^(true|false|yes|no|null|on|off)$/i.test(value) // is a YAML keyword
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function formatYamlKey(key: string) {
|
|
14
|
+
return /[@/_.]/.test(key) ? `"${key}"` : key;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function formatYamlValue(value: string, indent: number) {
|
|
18
|
+
if (value.includes('\n')) {
|
|
19
|
+
const indentedValue = value
|
|
20
|
+
.split('\n')
|
|
21
|
+
.map((line) => `${' '.repeat(indent)}${line}`)
|
|
22
|
+
.join('\n');
|
|
23
|
+
|
|
24
|
+
// Return the block indicator on the same line as the content
|
|
25
|
+
return `|${indentedValue ? '\n' + indentedValue : ''}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (needsQuoting(value)) {
|
|
29
|
+
if (value.includes("'") && !value.includes('"')) {
|
|
30
|
+
return `"${value.replace(/["\\]/g, '\\$&')}"`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function toYaml(obj: unknown, indent = 0): string {
|
|
40
|
+
const spaces = ' '.repeat(indent);
|
|
41
|
+
|
|
42
|
+
if (obj == null) return '';
|
|
43
|
+
|
|
44
|
+
if (Array.isArray(obj)) {
|
|
45
|
+
return obj.map((item) => `${spaces}- ${toYaml(item, indent + 2).trimStart()}`).join('\n');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (typeof obj === 'object') {
|
|
49
|
+
return Object.entries(obj)
|
|
50
|
+
.filter(([, v]) => v != null)
|
|
51
|
+
.map(([key, value]) => {
|
|
52
|
+
const formattedKey = formatYamlKey(key);
|
|
53
|
+
const formattedValue = toYaml(value, indent + 2);
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
return `${spaces}${formattedKey}:\n${formattedValue}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (typeof value === 'object' && value !== null) {
|
|
60
|
+
return `${spaces}${formattedKey}:\n${formattedValue}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (typeof value === 'string' && value.includes('\n')) {
|
|
64
|
+
return `${spaces}${formattedKey}: ${formattedValue}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return `${spaces}${formattedKey}: ${formattedValue}`;
|
|
68
|
+
})
|
|
69
|
+
.join('\n');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return typeof obj === 'string' ? formatYamlValue(obj, indent) : String(obj);
|
|
73
|
+
}
|