react-native-legal 1.0.0-next.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -0
  3. package/ReactNativeLegal.podspec +46 -0
  4. package/android/build.gradle +75 -0
  5. package/android/react-native-helpers.gradle +45 -0
  6. package/android/src/main/java/com/reactnativelegal/ReactNativeLegalActivity.kt +98 -0
  7. package/android/src/main/java/com/reactnativelegal/ReactNativeLegalModuleImpl.kt +19 -0
  8. package/android/src/main/java/com/reactnativelegal/ReactNativeLegalTurboPackage.kt +38 -0
  9. package/android/src/main/res/layout/activity_licenses.xml +28 -0
  10. package/android/src/main/res/values/styles.xml +7 -0
  11. package/android/src/main/res/values-v29/styles.xml +8 -0
  12. package/android/src/newarch/java/com/reactnativelegal/ReactNativeLegalModule.kt +17 -0
  13. package/android/src/oldarch/java/com/reactnativelegal/ReactNativeLegalModule.kt +23 -0
  14. package/app.plugin.js +1 -0
  15. package/bare-plugin/build/android/addListActivity.d.ts +4 -0
  16. package/bare-plugin/build/android/addListActivity.js +22 -0
  17. package/bare-plugin/build/android/androidCommand.d.ts +7 -0
  18. package/bare-plugin/build/android/androidCommand.js +25 -0
  19. package/bare-plugin/build/android/applyAndConfigureAboutLibrariesPlugin.d.ts +6 -0
  20. package/bare-plugin/build/android/applyAndConfigureAboutLibrariesPlugin.js +27 -0
  21. package/bare-plugin/build/android/declareAboutLibrariesPlugin.d.ts +6 -0
  22. package/bare-plugin/build/android/declareAboutLibrariesPlugin.js +27 -0
  23. package/bare-plugin/build/android/utils.d.ts +14 -0
  24. package/bare-plugin/build/android/utils.js +37 -0
  25. package/bare-plugin/build/index.d.ts +2 -0
  26. package/bare-plugin/build/index.js +9 -0
  27. package/bare-plugin/build/ios/addSettingsBundle.d.ts +4 -0
  28. package/bare-plugin/build/ios/addSettingsBundle.js +27 -0
  29. package/bare-plugin/build/ios/iosCommand.d.ts +7 -0
  30. package/bare-plugin/build/ios/iosCommand.js +23 -0
  31. package/bare-plugin/build/ios/registerLicensePlistBuildPhase.d.ts +7 -0
  32. package/bare-plugin/build/ios/registerLicensePlistBuildPhase.js +24 -0
  33. package/bare-plugin/build/ios/utils.d.ts +33 -0
  34. package/bare-plugin/build/ios/utils.js +98 -0
  35. package/bare-plugin/src/android/addListActivity.ts +22 -0
  36. package/bare-plugin/src/android/androidCommand.ts +23 -0
  37. package/bare-plugin/src/android/applyAndConfigureAboutLibrariesPlugin.ts +21 -0
  38. package/bare-plugin/src/android/declareAboutLibrariesPlugin.ts +21 -0
  39. package/bare-plugin/src/android/utils.ts +34 -0
  40. package/bare-plugin/src/index.ts +9 -0
  41. package/bare-plugin/src/ios/addSettingsBundle.ts +27 -0
  42. package/bare-plugin/src/ios/iosCommand.ts +21 -0
  43. package/bare-plugin/src/ios/registerLicensePlistBuildPhase.ts +22 -0
  44. package/bare-plugin/src/ios/utils.ts +120 -0
  45. package/bare-plugin/tsconfig.json +20 -0
  46. package/ios/ReactNativeLegal-Bridging-Header.h +1 -0
  47. package/ios/ReactNativeLegalDetailViewController.swift +156 -0
  48. package/ios/ReactNativeLegalLicenseMetadata.swift +4 -0
  49. package/ios/ReactNativeLegalModule.h +7 -0
  50. package/ios/ReactNativeLegalModule.mm +29 -0
  51. package/ios/ReactNativeLegalModuleImpl.swift +78 -0
  52. package/ios/ReactNativeLegalTableViewController.swift +72 -0
  53. package/lib/commonjs/NativeReactNativeLegal.js +10 -0
  54. package/lib/commonjs/NativeReactNativeLegal.js.map +1 -0
  55. package/lib/commonjs/ReactNativeLegal.android.js +18 -0
  56. package/lib/commonjs/ReactNativeLegal.android.js.map +1 -0
  57. package/lib/commonjs/ReactNativeLegal.ios.js +18 -0
  58. package/lib/commonjs/ReactNativeLegal.ios.js.map +1 -0
  59. package/lib/commonjs/ReactNativeLegal.js +13 -0
  60. package/lib/commonjs/ReactNativeLegal.js.map +1 -0
  61. package/lib/commonjs/index.js +13 -0
  62. package/lib/commonjs/index.js.map +1 -0
  63. package/lib/module/NativeReactNativeLegal.js +3 -0
  64. package/lib/module/NativeReactNativeLegal.js.map +1 -0
  65. package/lib/module/ReactNativeLegal.android.js +10 -0
  66. package/lib/module/ReactNativeLegal.android.js.map +1 -0
  67. package/lib/module/ReactNativeLegal.ios.js +10 -0
  68. package/lib/module/ReactNativeLegal.ios.js.map +1 -0
  69. package/lib/module/ReactNativeLegal.js +6 -0
  70. package/lib/module/ReactNativeLegal.js.map +1 -0
  71. package/lib/module/index.js +2 -0
  72. package/lib/module/index.js.map +1 -0
  73. package/lib/typescript/NativeReactNativeLegal.d.ts +7 -0
  74. package/lib/typescript/NativeReactNativeLegal.d.ts.map +1 -0
  75. package/lib/typescript/ReactNativeLegal.android.d.ts +4 -0
  76. package/lib/typescript/ReactNativeLegal.android.d.ts.map +1 -0
  77. package/lib/typescript/ReactNativeLegal.d.ts +4 -0
  78. package/lib/typescript/ReactNativeLegal.d.ts.map +1 -0
  79. package/lib/typescript/ReactNativeLegal.ios.d.ts +4 -0
  80. package/lib/typescript/ReactNativeLegal.ios.d.ts.map +1 -0
  81. package/lib/typescript/index.d.ts +2 -0
  82. package/lib/typescript/index.d.ts.map +1 -0
  83. package/package.json +97 -0
  84. package/plugin/build/android/addListActivity.d.ts +5 -0
  85. package/plugin/build/android/addListActivity.js +17 -0
  86. package/plugin/build/android/applyAndConfigureAboutLibrariesPlugin.d.ts +7 -0
  87. package/plugin/build/android/applyAndConfigureAboutLibrariesPlugin.js +22 -0
  88. package/plugin/build/android/declareAboutLibrariesPlugin.d.ts +7 -0
  89. package/plugin/build/android/declareAboutLibrariesPlugin.js +22 -0
  90. package/plugin/build/android/withAndroidLegal.d.ts +8 -0
  91. package/plugin/build/android/withAndroidLegal.js +30 -0
  92. package/plugin/build/index.d.ts +3 -0
  93. package/plugin/build/index.js +11 -0
  94. package/plugin/build/ios/addSettingsBundle.d.ts +5 -0
  95. package/plugin/build/ios/addSettingsBundle.js +28 -0
  96. package/plugin/build/ios/registerLicensePlistBuildPhase.d.ts +8 -0
  97. package/plugin/build/ios/registerLicensePlistBuildPhase.js +23 -0
  98. package/plugin/build/ios/withIosLegal.d.ts +8 -0
  99. package/plugin/build/ios/withIosLegal.js +28 -0
  100. package/plugin/jest.config.js +1 -0
  101. package/plugin/src/android/addListActivity.ts +19 -0
  102. package/plugin/src/android/applyAndConfigureAboutLibrariesPlugin.ts +23 -0
  103. package/plugin/src/android/declareAboutLibrariesPlugin.ts +21 -0
  104. package/plugin/src/android/withAndroidLegal.ts +28 -0
  105. package/plugin/src/index.ts +14 -0
  106. package/plugin/src/ios/addSettingsBundle.ts +29 -0
  107. package/plugin/src/ios/registerLicensePlistBuildPhase.ts +24 -0
  108. package/plugin/src/ios/withIosLegal.ts +26 -0
  109. package/plugin/tsconfig.json +9 -0
  110. package/plugin-utils/build/android.d.ts +12 -0
  111. package/plugin-utils/build/android.js +91 -0
  112. package/plugin-utils/build/common.d.ts +45 -0
  113. package/plugin-utils/build/common.js +312 -0
  114. package/plugin-utils/build/ios.d.ts +11 -0
  115. package/plugin-utils/build/ios.js +86 -0
  116. package/plugin-utils/src/android.ts +99 -0
  117. package/plugin-utils/src/common.ts +398 -0
  118. package/plugin-utils/src/ios.ts +102 -0
  119. package/plugin-utils/tsconfig.json +20 -0
  120. package/react-native.config.js +13 -0
  121. package/src/NativeReactNativeLegal.ts +8 -0
  122. package/src/ReactNativeLegal.android.ts +10 -0
  123. package/src/ReactNativeLegal.ios.ts +10 -0
  124. package/src/ReactNativeLegal.ts +5 -0
  125. package/src/index.ts +1 -0
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addListActivityUtil = exports.applyAndConfigureAboutLibrariesPluginUtil = exports.declareAboutLibrariesPluginUtil = void 0;
4
+ const common_1 = require("./common");
5
+ /**
6
+ * Applies Gradle Plugin Portal & AboutLibraries Gradle plugin repositories (if needed) inside root build.gradle
7
+ */
8
+ function declareAboutLibrariesPluginUtil(androidBuildGradleContent) {
9
+ if (!androidBuildGradleContent.match(PLUGIN_CLASSPATH)?.length) {
10
+ // Add Gradle Plugin Portal repository if it's not included
11
+ if (!androidBuildGradleContent.match(GRADLE_PLUGIN_PORTAL_URL)?.length) {
12
+ androidBuildGradleContent = androidBuildGradleContent.replace(/repositories\s?{/, `repositories {\n maven { url = uri("${GRADLE_PLUGIN_PORTAL_URL}") }`);
13
+ console.log('Gradle Plugin Portal repository - ADDED');
14
+ }
15
+ else {
16
+ console.log('Gradle Plugin Portal repository already added - SKIP');
17
+ }
18
+ // Declare the AboutLibraries plugin
19
+ androidBuildGradleContent = androidBuildGradleContent.replace(/dependencies\s?{/, `dependencies {\n classpath("${PLUGIN_CLASSPATH}:${PLUGIN_VERSION}")`);
20
+ console.log('About Libraries Gradle Plugin repository - ADDED');
21
+ }
22
+ else {
23
+ console.log('About Libraries Gradle Plugin already added - SKIP');
24
+ }
25
+ return androidBuildGradleContent;
26
+ }
27
+ exports.declareAboutLibrariesPluginUtil = declareAboutLibrariesPluginUtil;
28
+ /**
29
+ * Applies and configures AboutLibraries Grale plugin (if needed) inside app's build.gradle
30
+ */
31
+ function applyAndConfigureAboutLibrariesPluginUtil(androidAppBuildGradleContent) {
32
+ // Apply plugin
33
+ const applyPluginBlockRegex = new RegExp(`apply\\s+plugin:\\s+['"]${PLUGIN_APPLY_BLOCK_IDENTIFIER}['"]`);
34
+ if (!androidAppBuildGradleContent.match(applyPluginBlockRegex)?.length) {
35
+ androidAppBuildGradleContent += `\n${PLUGIN_APPLY_BLOCK}`;
36
+ console.log('About Libraries Gradle Plugin - APPLIED');
37
+ }
38
+ else {
39
+ console.log('About Libraries Gradle Plugin already applied - SKIP');
40
+ }
41
+ // Configure plugin
42
+ const pluginConfigRegex = /aboutLibraries {/;
43
+ if (!androidAppBuildGradleContent.match(pluginConfigRegex)?.length) {
44
+ androidAppBuildGradleContent += '\n\naboutLibraries {\n configPath = "config"\n prettyPrint = true\n}';
45
+ console.log('About Libraries Gradle Plugin - CONFIGURED');
46
+ }
47
+ else {
48
+ console.log('About Libraries Gradle Plugin already configured - SKIP');
49
+ }
50
+ return androidAppBuildGradleContent;
51
+ }
52
+ exports.applyAndConfigureAboutLibrariesPluginUtil = applyAndConfigureAboutLibrariesPluginUtil;
53
+ /**
54
+ * adds a list activity to the list of application's activities
55
+ */
56
+ function addListActivityUtil(activities) {
57
+ const listActivity = prepareListActivity();
58
+ if (!(0, common_1.arrayIncludesObject)(activities, listActivity)) {
59
+ activities?.push(listActivity);
60
+ console.log('About Libraries activity - ADDED');
61
+ }
62
+ else {
63
+ console.log('About Libraries activity already added - SKIP');
64
+ }
65
+ return activities;
66
+ }
67
+ exports.addListActivityUtil = addListActivityUtil;
68
+ /**
69
+ * This JS object will evaluate to the following XML content:
70
+ *
71
+ * <activity
72
+ * android:name="com.reactnativelegal.ReactNativeLegalActivity"
73
+ * android:exported="false"
74
+ * android:launchMode="singleTask"
75
+ * />
76
+ */
77
+ function prepareListActivity() {
78
+ return {
79
+ $: {
80
+ 'android:name': PLUGIN_ACTIVITY,
81
+ 'android:exported': 'false',
82
+ 'android:launchMode': 'singleTask',
83
+ },
84
+ };
85
+ }
86
+ const GRADLE_PLUGIN_PORTAL_URL = 'https://plugins.gradle.org/m2';
87
+ const PLUGIN_ACTIVITY = 'com.reactnativelegal.ReactNativeLegalActivity';
88
+ const PLUGIN_APPLY_BLOCK = "apply plugin: 'com.mikepenz.aboutlibraries.plugin'";
89
+ const PLUGIN_APPLY_BLOCK_IDENTIFIER = 'com.mikepenz.aboutlibraries.plugin';
90
+ const PLUGIN_CLASSPATH = 'com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin';
91
+ const PLUGIN_VERSION = '11.6.3';
@@ -0,0 +1,45 @@
1
+ type LicenseObj = {
2
+ author?: string;
3
+ content?: string;
4
+ description?: string;
5
+ type?: string;
6
+ url?: string;
7
+ version: string;
8
+ };
9
+ /**
10
+ * Makes a deep-check between array items and provided object, returns true if array has provided object.
11
+ */
12
+ export declare function arrayIncludesObject(array?: unknown[], object?: unknown): boolean | undefined;
13
+ /**
14
+ * Scans `package.json` and searches for all packages under `dependencies` field. Supports monorepo projects.
15
+ */
16
+ export declare function scanDependencies(appPackageJsonPath: string): Record<string, LicenseObj>;
17
+ /**
18
+ * Generates LicensePlist-compatible metadata for NPM dependencies
19
+ *
20
+ * This will take scanned NPM licenses and produce following output inside iOS project's directory:
21
+ *
22
+ * | - ios
23
+ * | ---- myawesomeapp
24
+ * | ---- myawesomeapp.xcodeproj
25
+ * | ---- myawesomeapp.xcodeworkspace
26
+ * | ---- license_plist.yml <--- generated LicensePlist config with NPM dependencies
27
+ * | ---- Podfile
28
+ * | ---- Podfile.lock
29
+ */
30
+ export declare function generateLicensePlistNPMOutput(licenses: Record<string, LicenseObj>, iosProjectPath: string): void;
31
+ /**
32
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
33
+ *
34
+ * This will take scanned NPM licenses and produce following output inside android project's directory:
35
+ *
36
+ * | - android
37
+ * | ---- app
38
+ * | ---- config <--- generated AboutLibraries config directory
39
+ * | ------- libraries <--- generated directory with JSON files list of NPM dependencies
40
+ * | ------- licenses <--- generated directory with JSON files list of used licenses
41
+ * | ---- build.gradle
42
+ * | ---- settings.gradle
43
+ */
44
+ export declare function generateAboutLibrariesNPMOutput(licenses: Record<string, LicenseObj>, androidProjectPath: string): void;
45
+ export {};
@@ -0,0 +1,312 @@
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.generateAboutLibrariesNPMOutput = exports.generateLicensePlistNPMOutput = exports.scanDependencies = exports.arrayIncludesObject = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const glob = require('glob');
11
+ function compareObjects(a, b) {
12
+ if (a == null || b == null || typeof a !== 'object' || typeof b !== 'object') {
13
+ return a === b;
14
+ }
15
+ const entriesA = Object.entries(a);
16
+ const entriesB = Object.entries(b);
17
+ return (entriesA.length === entriesB.length &&
18
+ entriesA
19
+ .map(([keyA, valueA]) => {
20
+ const entry = entriesB.find(([keyB]) => keyA === keyB);
21
+ if (!entry) {
22
+ return valueA === entry;
23
+ }
24
+ const [, valueB] = entry;
25
+ return compareObjects(valueA, valueB);
26
+ })
27
+ .reduce((acc, curr) => acc && curr, true));
28
+ }
29
+ /**
30
+ * Makes a deep-check between array items and provided object, returns true if array has provided object.
31
+ */
32
+ function arrayIncludesObject(array, object) {
33
+ return array?.map((item) => compareObjects(item, object)).reduce((acc, curr) => acc || curr, false);
34
+ }
35
+ exports.arrayIncludesObject = arrayIncludesObject;
36
+ /**
37
+ * Scans `package.json` and searches for all packages under `dependencies` field. Supports monorepo projects.
38
+ */
39
+ function scanDependencies(appPackageJsonPath) {
40
+ const appPackageJson = require(path_1.default.resolve(appPackageJsonPath));
41
+ const dependencies = appPackageJson.dependencies;
42
+ return Object.keys(dependencies).reduce((acc, dependency) => {
43
+ try {
44
+ const localPackageJsonPath = getPackageJsonPath(dependency);
45
+ if (!localPackageJsonPath) {
46
+ console.warn(`[react-native-legal] skipping ${dependency} could not find package.json`);
47
+ return acc;
48
+ }
49
+ const localPackageJson = require(path_1.default.resolve(localPackageJsonPath));
50
+ const licenseFiles = glob.sync('LICEN{S,C}E{.md,}', {
51
+ cwd: path_1.default.dirname(localPackageJsonPath),
52
+ absolute: true,
53
+ nocase: true,
54
+ nodir: true,
55
+ ignore: '**/{__tests__,__fixtures__,__mocks__}/**',
56
+ });
57
+ acc[dependency] = {
58
+ author: parseAuthorField(localPackageJson),
59
+ content: licenseFiles?.[0] ? fs_1.default.readFileSync(licenseFiles[0], { encoding: 'utf-8' }) : undefined,
60
+ description: localPackageJson.description,
61
+ type: parseLicenseField(localPackageJson),
62
+ url: parseRepositoryFieldToUrl(localPackageJson),
63
+ version: localPackageJson.version,
64
+ };
65
+ }
66
+ catch (error) {
67
+ console.warn(`[react-native-legal] could not process package.json for ${dependency}`);
68
+ }
69
+ return acc;
70
+ }, {});
71
+ }
72
+ exports.scanDependencies = scanDependencies;
73
+ function needsQuoting(value) {
74
+ return (value === '' || // empty string
75
+ /^[#:>|-]/.test(value) || // starts with special char
76
+ /^['"{}[\],&*#?|<>=!%@`]/.test(value) || // starts with indicator chars
77
+ /^[\s]|[\s]$/.test(value) || // has leading/trailing whitespace
78
+ /^[\d.+-]/.test(value) || // looks like a number/bool/null
79
+ /[\n"'\\\s]/.test(value) || // contains newlines, quotes, backslash, or spaces
80
+ /^(true|false|yes|no|null|on|off)$/i.test(value) // is a YAML keyword
81
+ );
82
+ }
83
+ function formatYamlKey(key) {
84
+ return /[@/_.]/.test(key) ? `"${key}"` : key;
85
+ }
86
+ function formatYamlValue(value, indent) {
87
+ if (value.includes('\n')) {
88
+ const indentedValue = value
89
+ .split('\n')
90
+ .map((line) => `${' '.repeat(indent)}${line}`)
91
+ .join('\n');
92
+ // Return the block indicator on the same line as the content
93
+ return `|${indentedValue ? '\n' + indentedValue : ''}`;
94
+ }
95
+ if (needsQuoting(value)) {
96
+ if (value.includes("'") && !value.includes('"')) {
97
+ return `"${value.replace(/["\\]/g, '\\$&')}"`;
98
+ }
99
+ return `'${value.replace(/'/g, "''")}'`;
100
+ }
101
+ return value;
102
+ }
103
+ function toYaml(obj, indent = 0) {
104
+ const spaces = ' '.repeat(indent);
105
+ if (obj == null)
106
+ return '';
107
+ if (Array.isArray(obj)) {
108
+ return obj.map((item) => `${spaces}- ${toYaml(item, indent + 2).trimStart()}`).join('\n');
109
+ }
110
+ if (typeof obj === 'object') {
111
+ return Object.entries(obj)
112
+ .filter(([, v]) => v != null)
113
+ .map(([key, value]) => {
114
+ const formattedKey = formatYamlKey(key);
115
+ const formattedValue = toYaml(value, indent + 2);
116
+ if (Array.isArray(value)) {
117
+ return `${spaces}${formattedKey}:\n${formattedValue}`;
118
+ }
119
+ if (typeof value === 'object' && value !== null) {
120
+ return `${spaces}${formattedKey}:\n${formattedValue}`;
121
+ }
122
+ if (typeof value === 'string' && value.includes('\n')) {
123
+ return `${spaces}${formattedKey}: ${formattedValue}`;
124
+ }
125
+ return `${spaces}${formattedKey}: ${formattedValue}`;
126
+ })
127
+ .join('\n');
128
+ }
129
+ return typeof obj === 'string' ? formatYamlValue(obj, indent) : String(obj);
130
+ }
131
+ /**
132
+ * Generates LicensePlist-compatible metadata for NPM dependencies
133
+ *
134
+ * This will take scanned NPM licenses and produce following output inside iOS project's directory:
135
+ *
136
+ * | - ios
137
+ * | ---- myawesomeapp
138
+ * | ---- myawesomeapp.xcodeproj
139
+ * | ---- myawesomeapp.xcodeworkspace
140
+ * | ---- license_plist.yml <--- generated LicensePlist config with NPM dependencies
141
+ * | ---- Podfile
142
+ * | ---- Podfile.lock
143
+ */
144
+ function generateLicensePlistNPMOutput(licenses, iosProjectPath) {
145
+ const renames = {};
146
+ const licenseEntries = Object.entries(licenses).map(([dependency, licenseObj]) => {
147
+ const normalizedName = normalizePackageName(dependency);
148
+ if (dependency !== normalizedName) {
149
+ renames[normalizedName] = dependency;
150
+ }
151
+ return {
152
+ name: normalizedName,
153
+ version: licenseObj.version,
154
+ ...(licenseObj.url && { source: licenseObj.url }),
155
+ body: licenseObj.content ?? licenseObj.type ?? 'UNKNOWN',
156
+ };
157
+ });
158
+ const yamlDoc = {
159
+ ...(Object.keys(renames).length > 0 && { rename: renames }),
160
+ manual: licenseEntries,
161
+ };
162
+ const yamlContent = [
163
+ '# BEGIN Generated NPM license entries',
164
+ toYaml(yamlDoc),
165
+ '# END Generated NPM license entries',
166
+ ].join('\n');
167
+ fs_1.default.writeFileSync(path_1.default.join(iosProjectPath, 'license_plist.yml'), yamlContent, { encoding: 'utf-8' });
168
+ }
169
+ exports.generateLicensePlistNPMOutput = generateLicensePlistNPMOutput;
170
+ /**
171
+ * Generates AboutLibraries-compatible metadata for NPM dependencies
172
+ *
173
+ * This will take scanned NPM licenses and produce following output inside android project's directory:
174
+ *
175
+ * | - android
176
+ * | ---- app
177
+ * | ---- config <--- generated AboutLibraries config directory
178
+ * | ------- libraries <--- generated directory with JSON files list of NPM dependencies
179
+ * | ------- licenses <--- generated directory with JSON files list of used licenses
180
+ * | ---- build.gradle
181
+ * | ---- settings.gradle
182
+ */
183
+ function generateAboutLibrariesNPMOutput(licenses, androidProjectPath) {
184
+ const aboutLibrariesConfigDirPath = path_1.default.join(androidProjectPath, 'config');
185
+ const aboutLibrariesConfigLibrariesDirPath = path_1.default.join(aboutLibrariesConfigDirPath, 'libraries');
186
+ const aboutLibrariesConfigLicensesDirPath = path_1.default.join(aboutLibrariesConfigDirPath, 'licenses');
187
+ if (!fs_1.default.existsSync(aboutLibrariesConfigDirPath)) {
188
+ fs_1.default.mkdirSync(aboutLibrariesConfigDirPath);
189
+ }
190
+ if (!fs_1.default.existsSync(aboutLibrariesConfigLibrariesDirPath)) {
191
+ fs_1.default.mkdirSync(aboutLibrariesConfigLibrariesDirPath);
192
+ }
193
+ if (!fs_1.default.existsSync(aboutLibrariesConfigLicensesDirPath)) {
194
+ fs_1.default.mkdirSync(aboutLibrariesConfigLicensesDirPath);
195
+ }
196
+ Object.entries(licenses)
197
+ .map(([dependency, licenseObj]) => {
198
+ return {
199
+ artifactVersion: licenseObj.version,
200
+ content: licenseObj.content ?? '',
201
+ description: licenseObj.description ?? '',
202
+ developers: [{ name: licenseObj.author ?? '', organisationUrl: '' }],
203
+ licenses: [prepareAboutLibrariesLicenseField(licenseObj)],
204
+ name: dependency,
205
+ tag: '',
206
+ type: licenseObj.type,
207
+ uniqueId: normalizePackageName(dependency),
208
+ };
209
+ })
210
+ .map((jsonPayload) => {
211
+ const libraryJsonPayload = {
212
+ artifactVersion: jsonPayload.artifactVersion,
213
+ description: jsonPayload.description,
214
+ developers: jsonPayload.developers,
215
+ licenses: jsonPayload.licenses,
216
+ name: jsonPayload.name,
217
+ tag: jsonPayload.tag,
218
+ uniqueId: jsonPayload.uniqueId,
219
+ };
220
+ const licenseJsonPayload = {
221
+ content: jsonPayload.content,
222
+ hash: jsonPayload.licenses[0],
223
+ name: jsonPayload.type ?? '',
224
+ url: '',
225
+ };
226
+ const libraryJsonFilePath = path_1.default.join(aboutLibrariesConfigLibrariesDirPath, `${normalizePackageName(jsonPayload.name)}.json`);
227
+ const licenseJsonFilePath = path_1.default.join(aboutLibrariesConfigLicensesDirPath, `${licenseJsonPayload.hash}.json`);
228
+ fs_1.default.writeFileSync(libraryJsonFilePath, JSON.stringify(libraryJsonPayload));
229
+ if (!fs_1.default.existsSync(licenseJsonFilePath)) {
230
+ fs_1.default.writeFileSync(licenseJsonFilePath, JSON.stringify(licenseJsonPayload));
231
+ }
232
+ });
233
+ }
234
+ exports.generateAboutLibrariesNPMOutput = generateAboutLibrariesNPMOutput;
235
+ function prepareAboutLibrariesLicenseField(license) {
236
+ if (!license.type) {
237
+ return '';
238
+ }
239
+ return `${license.type}_${sha512(license.content ?? license.type)}`;
240
+ }
241
+ function sha512(text) {
242
+ return crypto_1.default.createHash('sha512').update(text).digest('hex');
243
+ }
244
+ function parseAuthorField(json) {
245
+ if (typeof json.author === 'object' && typeof json.author.name === 'string') {
246
+ return json.author.name;
247
+ }
248
+ if (typeof json.author === 'string') {
249
+ return json.author;
250
+ }
251
+ }
252
+ function parseLicenseField(json) {
253
+ if (typeof json.license === 'object' && typeof json.license.type === 'string') {
254
+ return json.license.type;
255
+ }
256
+ if (typeof json.license === 'string') {
257
+ return json.license;
258
+ }
259
+ }
260
+ function parseRepositoryFieldToUrl(json) {
261
+ if (typeof json.repository === 'object' && typeof json.repository.url === 'string') {
262
+ return normalizeRepositoryUrl(json.repository.url);
263
+ }
264
+ if (typeof json.repository === 'string') {
265
+ return normalizeRepositoryUrl(json.repository);
266
+ }
267
+ }
268
+ function normalizeRepositoryUrl(url) {
269
+ return url
270
+ .replace('git+ssh://git@', 'git://')
271
+ .replace('.git', '')
272
+ .replace('git+https://github.com', 'https://github.com')
273
+ .replace('.git', '')
274
+ .replace('git://github.com', 'https://github.com')
275
+ .replace('.git', '')
276
+ .replace('git@github.com:', 'https://github.com/')
277
+ .replace('.git', '')
278
+ .replace('github:', 'https://github.com/')
279
+ .replace('.git', '');
280
+ }
281
+ function getPackageJsonPath(dependency) {
282
+ try {
283
+ return require.resolve(`${dependency}/package.json`);
284
+ }
285
+ catch (error) {
286
+ return resolvePackageJsonFromEntry(dependency);
287
+ }
288
+ }
289
+ function resolvePackageJsonFromEntry(dependency) {
290
+ try {
291
+ const entryPath = require.resolve(dependency);
292
+ const packageDir = findPackageRoot(entryPath);
293
+ if (!packageDir)
294
+ return null;
295
+ const packageJsonPath = path_1.default.join(packageDir, 'package.json');
296
+ return fs_1.default.existsSync(packageJsonPath) ? packageJsonPath : null;
297
+ }
298
+ catch {
299
+ return null;
300
+ }
301
+ }
302
+ function findPackageRoot(entryPath) {
303
+ let currentDir = path_1.default.dirname(entryPath);
304
+ while (currentDir !== path_1.default.dirname(currentDir)) {
305
+ if (fs_1.default.existsSync(path_1.default.join(currentDir, 'package.json')))
306
+ return currentDir;
307
+ currentDir = path_1.default.dirname(currentDir);
308
+ }
309
+ }
310
+ function normalizePackageName(packageName) {
311
+ return packageName.replace('/', '_');
312
+ }
@@ -0,0 +1,11 @@
1
+ import type { XcodeProject } from 'xcode';
2
+ /**
3
+ * Creates a Settings.bundle from a template and invokes a callback responsible for linking new file to the iOS project
4
+ */
5
+ export declare function addSettingsBundleUtil(iosProjectPath: string, addResourceFileToGroup: ({ settingsBundleFilename }: {
6
+ settingsBundleFilename: string;
7
+ }) => void): void;
8
+ /**
9
+ * Creates a shell script build phase (if needed) and links it to native targets build phases
10
+ */
11
+ export declare function registerLicensePlistBuildPhaseUtil(projectTargetId: string, pbxproj: XcodeProject): XcodeProject;
@@ -0,0 +1,86 @@
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.registerLicensePlistBuildPhaseUtil = exports.addSettingsBundleUtil = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ /**
10
+ * Creates a Settings.bundle from a template and invokes a callback responsible for linking new file to the iOS project
11
+ */
12
+ function addSettingsBundleUtil(iosProjectPath, addResourceFileToGroup) {
13
+ const settingsBundleFilename = 'Settings.bundle';
14
+ const settingsBundleRootPlistFilename = 'Root.plist';
15
+ const settingsBundlePath = path_1.default.join(iosProjectPath, settingsBundleFilename);
16
+ const settingsBundleRootPlistPath = path_1.default.join(settingsBundlePath, settingsBundleRootPlistFilename);
17
+ if (!fs_1.default.existsSync(settingsBundleRootPlistPath)) {
18
+ // Create `Settings.bundle` directory
19
+ if (!fs_1.default.existsSync(settingsBundlePath)) {
20
+ fs_1.default.mkdirSync(settingsBundlePath, { recursive: true });
21
+ }
22
+ // Create `Settings.bundle/Root.plist`
23
+ fs_1.default.writeFileSync(settingsBundleRootPlistPath, SETTINGS_BUNDLE_ROOT_PLIST_CONTENT);
24
+ // Link `Settings.bundle` to the resources
25
+ addResourceFileToGroup({ settingsBundleFilename });
26
+ console.log('Settings.bundle/Root.plist - ADDED');
27
+ }
28
+ else {
29
+ console.log('Settings.bundle/Root.plist already present - SKIP');
30
+ }
31
+ }
32
+ exports.addSettingsBundleUtil = addSettingsBundleUtil;
33
+ /**
34
+ * Creates a shell script build phase (if needed) and links it to native targets build phases
35
+ */
36
+ function registerLicensePlistBuildPhaseUtil(projectTargetId, pbxproj) {
37
+ const nativeTargetSection = pbxproj.pbxNativeTargetSection();
38
+ const nativeTarget = nativeTargetSection[projectTargetId];
39
+ if (pbxproj.buildPhase(GENERATE_LICENSE_PLIST_BUILD_PHASE_COMMENT, projectTargetId)) {
40
+ console.log(`LicensePlist buildPhase already added in "${nativeTarget.name}" - SKIP`);
41
+ return pbxproj;
42
+ }
43
+ /**
44
+ * The build phase will generate licenses metadata using `LicensePlist` library and store it inside `Settings.bundle`.
45
+ *
46
+ * This will return an object with the uuid of the newly created build phase and its associated comment.
47
+ */
48
+ const newBuildPhase = pbxproj.addBuildPhase([], 'PBXShellScriptBuildPhase', GENERATE_LICENSE_PLIST_BUILD_PHASE_COMMENT, projectTargetId, {
49
+ shellPath: '/bin/sh',
50
+ shellScript: '${PODS_ROOT}/LicensePlist/license-plist --output-path ./Settings.bundle',
51
+ });
52
+ /**
53
+ * In order to correctly link all metadata from `Settings.bundle` to the app
54
+ * the newly created build phase has to be invoked before `Copy Bundle Resources` build phase.
55
+ *
56
+ * To make sure that happens, let's put newly created build phase as a first in the sequence.
57
+ * It can be done by overriding `PBXNativeTarget["buildPhases"]` array.
58
+ */
59
+ const newBuildPhasesInNativeTarget = [
60
+ { value: newBuildPhase.uuid, comment: GENERATE_LICENSE_PLIST_BUILD_PHASE_COMMENT },
61
+ ].concat(nativeTarget.buildPhases.filter(({ value }) => value !== newBuildPhase.uuid));
62
+ nativeTarget.buildPhases = newBuildPhasesInNativeTarget;
63
+ console.log(`LicensePlist buildPhase in nativeTarget "${nativeTarget.name}" - ADDED`);
64
+ return pbxproj;
65
+ }
66
+ exports.registerLicensePlistBuildPhaseUtil = registerLicensePlistBuildPhaseUtil;
67
+ const GENERATE_LICENSE_PLIST_BUILD_PHASE_COMMENT = 'Generate licenses with LicensePlist';
68
+ const SETTINGS_BUNDLE_ROOT_PLIST_CONTENT = `<?xml version="1.0" encoding="UTF-8"?>
69
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
70
+ <plist version="1.0">
71
+ <dict>
72
+ <key>StringsTable</key>
73
+ <string>Root</string>
74
+ <key>PreferenceSpecifiers</key>
75
+ <array>
76
+ <dict>
77
+ <key>Type</key>
78
+ <string>PSChildPaneSpecifier</string>
79
+ <key>Title</key>
80
+ <string>Licenses</string>
81
+ <key>File</key>
82
+ <string>com.mono0926.LicensePlist</string>
83
+ </dict>
84
+ </array>
85
+ </dict>
86
+ </plist>`;
@@ -0,0 +1,99 @@
1
+ import { arrayIncludesObject } from './common';
2
+
3
+ /**
4
+ * Applies Gradle Plugin Portal & AboutLibraries Gradle plugin repositories (if needed) inside root build.gradle
5
+ */
6
+ export function declareAboutLibrariesPluginUtil(androidBuildGradleContent: string) {
7
+ if (!androidBuildGradleContent.match(PLUGIN_CLASSPATH)?.length) {
8
+ // Add Gradle Plugin Portal repository if it's not included
9
+ if (!androidBuildGradleContent.match(GRADLE_PLUGIN_PORTAL_URL)?.length) {
10
+ androidBuildGradleContent = androidBuildGradleContent.replace(
11
+ /repositories\s?{/,
12
+ `repositories {\n maven { url = uri("${GRADLE_PLUGIN_PORTAL_URL}") }`,
13
+ );
14
+ console.log('Gradle Plugin Portal repository - ADDED');
15
+ } else {
16
+ console.log('Gradle Plugin Portal repository already added - SKIP');
17
+ }
18
+
19
+ // Declare the AboutLibraries plugin
20
+ androidBuildGradleContent = androidBuildGradleContent.replace(
21
+ /dependencies\s?{/,
22
+ `dependencies {\n classpath("${PLUGIN_CLASSPATH}:${PLUGIN_VERSION}")`,
23
+ );
24
+ console.log('About Libraries Gradle Plugin repository - ADDED');
25
+ } else {
26
+ console.log('About Libraries Gradle Plugin already added - SKIP');
27
+ }
28
+
29
+ return androidBuildGradleContent;
30
+ }
31
+
32
+ /**
33
+ * Applies and configures AboutLibraries Grale plugin (if needed) inside app's build.gradle
34
+ */
35
+ export function applyAndConfigureAboutLibrariesPluginUtil(androidAppBuildGradleContent: string) {
36
+ // Apply plugin
37
+ const applyPluginBlockRegex = new RegExp(`apply\\s+plugin:\\s+['"]${PLUGIN_APPLY_BLOCK_IDENTIFIER}['"]`);
38
+
39
+ if (!androidAppBuildGradleContent.match(applyPluginBlockRegex)?.length) {
40
+ androidAppBuildGradleContent += `\n${PLUGIN_APPLY_BLOCK}`;
41
+ console.log('About Libraries Gradle Plugin - APPLIED');
42
+ } else {
43
+ console.log('About Libraries Gradle Plugin already applied - SKIP');
44
+ }
45
+
46
+ // Configure plugin
47
+ const pluginConfigRegex = /aboutLibraries {/;
48
+
49
+ if (!androidAppBuildGradleContent.match(pluginConfigRegex)?.length) {
50
+ androidAppBuildGradleContent += '\n\naboutLibraries {\n configPath = "config"\n prettyPrint = true\n}';
51
+ console.log('About Libraries Gradle Plugin - CONFIGURED');
52
+ } else {
53
+ console.log('About Libraries Gradle Plugin already configured - SKIP');
54
+ }
55
+
56
+ return androidAppBuildGradleContent;
57
+ }
58
+
59
+ /**
60
+ * adds a list activity to the list of application's activities
61
+ */
62
+ export function addListActivityUtil<T>(activities: T[]): T[] {
63
+ const listActivity = prepareListActivity();
64
+
65
+ if (!arrayIncludesObject(activities, listActivity)) {
66
+ activities?.push(listActivity as T);
67
+ console.log('About Libraries activity - ADDED');
68
+ } else {
69
+ console.log('About Libraries activity already added - SKIP');
70
+ }
71
+
72
+ return activities;
73
+ }
74
+
75
+ /**
76
+ * This JS object will evaluate to the following XML content:
77
+ *
78
+ * <activity
79
+ * android:name="com.reactnativelegal.ReactNativeLegalActivity"
80
+ * android:exported="false"
81
+ * android:launchMode="singleTask"
82
+ * />
83
+ */
84
+ function prepareListActivity() {
85
+ return {
86
+ $: {
87
+ 'android:name': PLUGIN_ACTIVITY,
88
+ 'android:exported': 'false',
89
+ 'android:launchMode': 'singleTask',
90
+ },
91
+ } as const;
92
+ }
93
+
94
+ const GRADLE_PLUGIN_PORTAL_URL = 'https://plugins.gradle.org/m2';
95
+ const PLUGIN_ACTIVITY = 'com.reactnativelegal.ReactNativeLegalActivity';
96
+ const PLUGIN_APPLY_BLOCK = "apply plugin: 'com.mikepenz.aboutlibraries.plugin'";
97
+ const PLUGIN_APPLY_BLOCK_IDENTIFIER = 'com.mikepenz.aboutlibraries.plugin';
98
+ const PLUGIN_CLASSPATH = 'com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin';
99
+ const PLUGIN_VERSION = '11.6.3';