-
Notifications
You must be signed in to change notification settings - Fork 915
feat(doctor): detect wrong dependencies #1983
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9dc5617
f5722cc
1bc6ced
7cb4171
ba99a67
1f6940e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import fs from 'fs'; | ||
import dependencies from '../dependencies'; | ||
import {EnvironmentInfo} from '../../../types'; | ||
|
||
describe('dependencies', () => { | ||
let environmentInfo: EnvironmentInfo; | ||
let dependenciesJSON: string; | ||
|
||
beforeEach(() => { | ||
jest.spyOn(fs, 'readFileSync').mockImplementation(() => dependenciesJSON); | ||
}); | ||
|
||
it('returns false if dependencies are correct', async () => { | ||
dependenciesJSON = JSON.stringify({ | ||
name: 'AwesomeProject', | ||
dependencies: { | ||
'react-native': '0.72.1', | ||
}, | ||
}); | ||
|
||
const diagnostics = await dependencies.getDiagnostics(environmentInfo); | ||
expect(diagnostics.needsToBeFixed).toBe(false); | ||
}); | ||
|
||
it('returns true if dependencies contains an incompatible version react native package', async () => { | ||
dependenciesJSON = JSON.stringify({ | ||
name: 'AwesomeProject', | ||
dependencies: { | ||
'react-native': '0.72.1', | ||
'@react-native/codegen': '1.72.3', | ||
'@react-native/gradle-plugin': '0.69.10', | ||
}, | ||
}); | ||
|
||
const diagnostics = await dependencies.getDiagnostics(environmentInfo); | ||
expect(diagnostics.needsToBeFixed).toBe(true); | ||
}); | ||
|
||
it('warn if dependencies contains an compatible version of react native packages', async () => { | ||
dependenciesJSON = JSON.stringify({ | ||
name: 'AwesomeProject', | ||
dependencies: { | ||
'react-native': '0.72.1', | ||
'@react-native/codegen': '0.72.1', | ||
}, | ||
}); | ||
|
||
const diagnostics = await dependencies.getDiagnostics(environmentInfo); | ||
expect(diagnostics.description).toMatch( | ||
'@react-native/codegen is part of React Native and should not be a dependency in your package.json', | ||
); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import fs from 'fs'; | ||
import chalk from 'chalk'; | ||
import path from 'path'; | ||
import semver from 'semver'; | ||
import {HealthCheckInterface} from '../../types'; | ||
import {logManualInstallation} from './common'; | ||
import {findProjectRoot, logger} from '@react-native-community/cli-tools'; | ||
|
||
const RNPackages = [ | ||
'@react-native/babel-plugin-codegen', | ||
'@react-native/assets-registry', | ||
'@react-native/eslint-plugin-specs', | ||
'@react-native/hermes-inspector-msggen', | ||
'@react-native/normalize-colors', | ||
'@react-native/js-polyfills', | ||
'@react-native/bots', | ||
'@react-native/codegen-typescript-test', | ||
'@react-native/codegen', | ||
'@react-native/gradle-plugin', | ||
'@react-native/virtualized-lists', | ||
]; | ||
|
||
const cliPackages = [ | ||
'@react-native-community/cli', | ||
'@react-native-community/cli-platform-android', | ||
'@react-native-community/cli-platform-ios', | ||
'@react-native-community/cli-tools', | ||
'@react-native-community/cli-doctor', | ||
'@react-native-community/cli-hermes', | ||
'@react-native-community/cli-clean', | ||
'@react-native-community/cli-config', | ||
'@react-native-community/cli-debugger-ui', | ||
'@react-native-community/cli-server-api', | ||
'@react-native-community/cli-types', | ||
]; | ||
|
||
const reactNativeCliCompatibilityMatrix = { | ||
12: ['0.73'], | ||
11: ['0.72'], | ||
10: ['0.71'], | ||
}; | ||
|
||
const getPackageJson = (root?: string): Record<string, any> => { | ||
try { | ||
root = root || findProjectRoot(); | ||
return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); | ||
} catch (e) { | ||
logger.log(); // for extra space | ||
logger.error(`Couldn't find a "package.json" in ${root || process.cwd()}.`); | ||
return {}; | ||
tarunrajput marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}; | ||
|
||
const findDependencies = (root?: string): Record<string, string> => { | ||
const {devDependencies = {}, dependencies = {}} = getPackageJson(root); | ||
return { | ||
...devDependencies, | ||
...dependencies, | ||
}; | ||
}; | ||
|
||
export default { | ||
label: 'Dependencies', | ||
isRequired: false, | ||
description: 'NPM dependencies needed for the project to work correctly', | ||
getDiagnostics: async (_, config) => { | ||
try { | ||
const dependencies = findDependencies(config?.root); | ||
const reactNativeVersion = dependencies['react-native']; | ||
const reactNativeCoercedVersion = semver.coerce(reactNativeVersion); | ||
const issues: string[] = []; | ||
|
||
RNPackages.forEach((pkg) => { | ||
if (dependencies[pkg]) { | ||
tarunrajput marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const packageVersion = dependencies[pkg]; | ||
const packageCoercedVersion = semver.coerce(packageVersion); | ||
if (reactNativeCoercedVersion && packageCoercedVersion) { | ||
const verisonDiff = semver.diff( | ||
packageCoercedVersion, | ||
reactNativeCoercedVersion, | ||
); | ||
if (verisonDiff === 'major' || verisonDiff === 'minor') { | ||
issues.push( | ||
` - ${chalk.red( | ||
'error', | ||
)} ${pkg}: "${packageVersion}" is not compatible with react-native: "${reactNativeVersion}"`, | ||
); | ||
Comment on lines
+84
to
+87
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could we use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for the suggestion! I chose not to use logger in this case because it would print the error/warning immediately outside of the issue category like this
|
||
} else { | ||
issues.push( | ||
` - ${chalk.yellow( | ||
'warn', | ||
)} ${pkg} is part of React Native and should not be a dependency in your package.json`, | ||
); | ||
} | ||
} | ||
} | ||
}); | ||
|
||
if (dependencies['react-native-cli']) { | ||
issues.push( | ||
` - ${chalk.red( | ||
'error', | ||
)} react-native-cli is legacy and should not be listed as a dependency in your package.json`, | ||
); | ||
} | ||
|
||
cliPackages.forEach((pkg) => { | ||
if (dependencies[pkg]) { | ||
const packageVersion = dependencies[pkg]; | ||
const packageMajorVersion = semver.coerce(packageVersion)?.major; | ||
const RNVersion = `${reactNativeCoercedVersion?.major}.${reactNativeCoercedVersion?.minor}`; | ||
|
||
if (packageMajorVersion) { | ||
const compatibleRNVersions = | ||
reactNativeCliCompatibilityMatrix[ | ||
packageMajorVersion as keyof typeof reactNativeCliCompatibilityMatrix | ||
] || []; | ||
if (!compatibleRNVersions.includes(RNVersion)) { | ||
issues.push( | ||
` - ${chalk.red( | ||
'error', | ||
)} ${pkg}: "${packageVersion}" is not compatible with react-native: "${reactNativeVersion}"`, | ||
); | ||
} else { | ||
issues.push( | ||
` - ${chalk.yellow( | ||
'warn', | ||
)} ${pkg} comes included with React Native and should not be listed as a dependency in your package.json`, | ||
); | ||
} | ||
} | ||
} | ||
}); | ||
|
||
if (issues.length) { | ||
issues.unshift('There are some issues with your project dependencies'); | ||
return { | ||
needsToBeFixed: true, | ||
description: issues.join('\n'), | ||
}; | ||
} else { | ||
return { | ||
needsToBeFixed: false, | ||
}; | ||
} | ||
} catch (e) { | ||
return { | ||
needsToBeFixed: true, | ||
}; | ||
} | ||
}, | ||
runAutomaticFix: async ({loader}) => { | ||
loader.fail(); | ||
return logManualInstallation({ | ||
message: | ||
'Please check your package.json and make sure the dependencies are correct', | ||
}); | ||
}, | ||
} as HealthCheckInterface; |
Uh oh!
There was an error while loading. Please reload this page.