[SCRIPT] Check Library Buildability script#163
Conversation
Checks: - Presence of native code - Compatibility with New Architecture - Custom react.native.config.js settings - Custom gradle plugins - Custom scripts - C++ code - `externalNativeBuild` settings - Dependencies on other libraries
There was a problem hiding this comment.
Pull request overview
This PR introduces a new library checker script that analyzes React Native libraries for buildability by examining their structural requirements. The script creates a temporary working directory, installs the specified library, and performs static analysis on the package structure, native code, Gradle configuration, and dependencies to determine if the library can be built successfully.
Key changes:
- Adds
library-checker.tsscript with comprehensive structural analysis capabilities - Updates
package.jsonto include thecheck-librarynpm script - Adds documentation to
README.mdexplaining the checker's purpose and usage - Updates ESLint config to ignore caught errors prefixed with underscore
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
| packages/builder/library-checker.ts | New script that performs static analysis on React Native libraries to check buildability, including native code detection, Gradle plugin analysis, C++ code detection, and dependency checking |
| packages/builder/package.json | Adds check-library script command for running the library checker |
| packages/builder/README.md | Documents the new library checker feature, its purpose, usage, and parameters |
| eslint.config.ts | Extends unused variable ignore pattern to include caught errors, supporting the underscore prefix convention used in the new script |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - Presence of native code | ||
| - Compatibility with New Architecture | ||
| - Custom gradle plugins | ||
| - Custom scripts |
There was a problem hiding this comment.
The README.md documentation mentions checking for "Custom scripts" but the script doesn't actually implement this check. Either remove this item from the documentation or implement the check in the script.
| - Custom scripts |
| .filter((line) => line.includes('id ')); | ||
| for (const line of pluginLines) { | ||
| if ( | ||
| !knownPlugins.some((plugin) => | ||
| line.includes(plugin) | ||
| ) | ||
| ) { | ||
| result.hasCustomGradlePlugins = true; | ||
| result.warnings.push( | ||
| `Custom gradle plugin detected: ${line.trim()}` |
There was a problem hiding this comment.
The checkGradlePlugins function checks for plugins with id but this will also match lines that contain "id" in other contexts (like variable names, comments, or string values). Consider using a more precise regex pattern like /id\s+['"]([^'"]+)['"]/ to match only plugin declarations.
| .filter((line) => line.includes('id ')); | |
| for (const line of pluginLines) { | |
| if ( | |
| !knownPlugins.some((plugin) => | |
| line.includes(plugin) | |
| ) | |
| ) { | |
| result.hasCustomGradlePlugins = true; | |
| result.warnings.push( | |
| `Custom gradle plugin detected: ${line.trim()}` | |
| .map((line) => { | |
| const match = line.match(/id\s+['"]([^'"]+)['"]/); | |
| return match ? match[1] : null; | |
| }) | |
| .filter((pluginName) => pluginName); | |
| for (const pluginName of pluginLines) { | |
| if (!knownPlugins.includes(pluginName)) { | |
| result.hasCustomGradlePlugins = true; | |
| result.warnings.push( | |
| `Custom gradle plugin detected: ${pluginName}` |
| const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); | ||
|
|
||
| // Check for native dependencies | ||
| const allDeps = { |
There was a problem hiding this comment.
The checkPackageJsonDependencies function only checks peerDependencies but not dependencies or devDependencies. This means native dependencies listed in the main dependencies field will be missed. Consider checking all dependency fields or clearly document why only peer dependencies are checked.
| const allDeps = { | |
| const allDeps = { | |
| ...packageJson.dependencies, | |
| ...packageJson.devDependencies, |
| return join(packageDir, 'apple'); | ||
| } | ||
| return join(packageDir, 'ios'); | ||
| } |
There was a problem hiding this comment.
Missing newline before the function declaration. According to TypeScript style conventions, there should be a blank line between function declarations for better readability and consistency with the rest of the file (see lines 52, 68, 86, 99, etc.).
| } | |
| } |
| ]; | ||
|
|
||
| for (const dep of Object.keys(allDeps || {})) { | ||
| if (!knownDependencies.some((knownDep) => dep.includes(knownDep))) { |
There was a problem hiding this comment.
The dependency filtering uses .includes() which can produce false positives. For example, a package named my-testing-library would be filtered out because it contains @testing in the knownDependencies array, even though it's not actually a testing library. Consider using more precise matching like checking if the dependency starts with the pattern (e.g., dep.startsWith(knownDep)) or exact matches for non-prefixed patterns.
| if (!knownDependencies.some((knownDep) => dep.includes(knownDep))) { | |
| if ( | |
| !knownDependencies.some((knownDep) => { | |
| if (knownDep.endsWith('/') || knownDep.startsWith('@')) { | |
| return dep.startsWith(knownDep); | |
| } else { | |
| return dep === knownDep; | |
| } | |
| }) | |
| ) { |
| 4. Building the library into an AAR artifact | ||
| 5. Publishing to Maven Local repository |
There was a problem hiding this comment.
The numbered list skips step 3. The sequence goes from step 2 directly to step 4. Consider adding the missing step 3 (likely "Configuring the build environment" or similar) or renumbering the steps to maintain proper sequence.
| 4. Building the library into an AAR artifact | |
| 5. Publishing to Maven Local repository | |
| 3. Building the library into an AAR artifact | |
| 4. Publishing to Maven Local repository |
| if (existsSync(buildGradleFile)) { | ||
| try { | ||
| const content = readFileSync(buildGradleFile, 'utf-8'); | ||
| if (content.includes('com.facebook.react')) { |
There was a problem hiding this comment.
The checkAndroidNewArchitectureSupport function only checks if the gradle file contains 'com.facebook.react' string, which is a very broad check. This could produce false positives since this string might appear in comments, dependency declarations, or other non-architecture-related contexts. Consider checking for more specific indicators of New Architecture support such as the presence of reactNativeArchitectures() function, newArchEnabled property, or React Native Codegen-related configurations.
| if (content.includes('com.facebook.react')) { | |
| // Look for more specific indicators of New Architecture support | |
| const hasReactNativeArchitectures = /reactNativeArchitectures\s*\(/.test(content); | |
| const hasNewArchEnabled = /newArchEnabled\s*[:=]\s*(true|['"]true['"])/.test(content); | |
| const hasCodegen = /react-native-codegen/.test(content); | |
| if (hasReactNativeArchitectures || hasNewArchEnabled || hasCodegen) { |
| * - Custom gradle plugins | ||
| * - C++ code | ||
| * - externalNativeBuild settings | ||
| * - Dependencies on other libraries |
There was a problem hiding this comment.
The script description says it checks for "Custom scripts" but there is no implementation that actually checks for custom scripts in package.json (like custom prebuild, postinstall, or other lifecycle scripts). Either remove this item from the description or implement the check.
📝 Description
Script that checks:
externalNativeBuildsettings🎯 Type of Change
Please delete options that are not relevant:
🧪 Testing
Please describe the tests you ran to verify your changes. Provide instructions so we can reproduce.