Skip to content

Commit 00b89fe

Browse files
onlyweiljharb
authored andcommitted
[New] version settings: Allow react defaultVersion to be configurable
1 parent 4d2fd86 commit 00b89fe

File tree

4 files changed

+79
-11
lines changed

4 files changed

+79
-11
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
1111
* add [`jsx-props-no-spread-multi`] ([#3724][] @SimonSchick)
1212
* [`forbid-component-props`]: add `propNamePattern` to allow / disallow prop name patterns ([#3774][] @akulsr0)
1313
* [`jsx-handler-names`]: support ignoring component names ([#3772][] @akulsr0)
14+
* version settings: Allow react defaultVersion to be configurable ([#3771][] @onlywei)
1415

1516
### Changed
1617
* [Refactor] `variableUtil`: Avoid creating a single flat variable scope for each lookup ([#3782][] @DanielRosenwasser)
1718

1819
[#3782]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3782
1920
[#3774]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3774
2021
[#3772]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3772
22+
[#3771]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3771
2123
[#3759]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3759
2224
[#3724]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3724
2325
[#3694]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3694

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ You should also specify settings that will be shared across all the plugin rules
4242
"fragment": "Fragment", // Fragment to use (may be a property of <pragma>), default to "Fragment"
4343
"version": "detect", // React version. "detect" automatically picks the version you have installed.
4444
// You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
45-
// It will default to "latest" and warn if missing, and to "detect" in the future
45+
// Defaults to the "defaultVersion" setting and warns if missing, and to "detect" in the future
46+
"defaultVersion": "", // Default React version to use when the version you have installed cannot be detected.
47+
// If not provided, defaults to the latest React version.
4648
"flowVersion": "0.53" // Flow version
4749
},
4850
"propWrapperFunctions": [

lib/util/version.js

+46-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const resolve = require('resolve');
1212
const semver = require('semver');
1313
const error = require('./error');
1414

15+
const ULTIMATE_LATEST_SEMVER = '999.999.999';
16+
1517
let warnedForMissingVersion = false;
1618

1719
function resetWarningFlag() {
@@ -44,6 +46,37 @@ function resolveBasedir(contextOrFilename) {
4446
return process.cwd();
4547
}
4648

49+
function convertConfVerToSemver(confVer) {
50+
const fullSemverString = /^[0-9]+\.[0-9]+$/.test(confVer) ? `${confVer}.0` : confVer;
51+
return semver.coerce(fullSemverString.split('.').map((part) => Number(part)).join('.'));
52+
}
53+
54+
let defaultVersion = ULTIMATE_LATEST_SEMVER;
55+
56+
function resetDefaultVersion() {
57+
defaultVersion = ULTIMATE_LATEST_SEMVER;
58+
}
59+
60+
function readDefaultReactVersionFromContext(context) {
61+
// .eslintrc shared settings (https://eslint.org/docs/user-guide/configuring#adding-shared-settings)
62+
if (context.settings && context.settings.react && context.settings.react.defaultVersion) {
63+
let settingsDefaultVersion = context.settings.react.defaultVersion;
64+
if (typeof settingsDefaultVersion !== 'string') {
65+
error('Warning: default React version specified in eslint-pluigin-react-settings must be a string; '
66+
+ `got "${typeof settingsDefaultVersion}"`);
67+
}
68+
settingsDefaultVersion = String(settingsDefaultVersion);
69+
const result = convertConfVerToSemver(settingsDefaultVersion);
70+
if (result) {
71+
defaultVersion = result.version;
72+
} else {
73+
error(`Warning: React version specified in eslint-plugin-react-settings must be a valid semver version, or "detect"; got “${settingsDefaultVersion}”. Falling back to latest version as default.`);
74+
}
75+
} else {
76+
defaultVersion = ULTIMATE_LATEST_SEMVER;
77+
}
78+
}
79+
4780
// TODO, semver-major: remove context fallback
4881
function detectReactVersion(context) {
4982
if (cachedDetectedReactVersion) {
@@ -60,20 +93,22 @@ function detectReactVersion(context) {
6093
} catch (e) {
6194
if (e.code === 'MODULE_NOT_FOUND') {
6295
if (!warnedForMissingVersion) {
63-
error('Warning: React version was set to "detect" in eslint-plugin-react settings, '
64-
+ 'but the "react" package is not installed. Assuming latest React version for linting.');
96+
let sentence2 = 'Assuming latest React version for linting.';
97+
if (defaultVersion !== ULTIMATE_LATEST_SEMVER) {
98+
sentence2 = `Assuming default React version for linting: "${defaultVersion}".`;
99+
}
100+
error(`Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. ${sentence2}`);
65101
warnedForMissingVersion = true;
66102
}
67-
cachedDetectedReactVersion = '999.999.999';
103+
cachedDetectedReactVersion = defaultVersion;
68104
return cachedDetectedReactVersion;
69105
}
70106
throw e;
71107
}
72108
}
73109

74-
const defaultVersion = '999.999.999';
75-
76110
function getReactVersionFromContext(context) {
111+
readDefaultReactVersionFromContext(context);
77112
let confVer = defaultVersion;
78113
// .eslintrc shared settings (https://eslint.org/docs/user-guide/configuring#adding-shared-settings)
79114
if (context.settings && context.settings.react && context.settings.react.version) {
@@ -91,8 +126,8 @@ function getReactVersionFromContext(context) {
91126
+ 'See https://github.com/jsx-eslint/eslint-plugin-react#configuration .');
92127
warnedForMissingVersion = true;
93128
}
94-
confVer = /^[0-9]+\.[0-9]+$/.test(confVer) ? `${confVer}.0` : confVer;
95-
const result = semver.coerce(confVer.split('.').map((part) => Number(part)).join('.'));
129+
130+
const result = convertConfVerToSemver(confVer);
96131
if (!result) {
97132
error(`Warning: React version specified in eslint-plugin-react-settings must be a valid semver version, or "detect"; got “${confVer}”`);
98133
}
@@ -111,7 +146,7 @@ function detectFlowVersion(context) {
111146
if (e.code === 'MODULE_NOT_FOUND') {
112147
error('Warning: Flow version was set to "detect" in eslint-plugin-react settings, '
113148
+ 'but the "flow-bin" package is not installed. Assuming latest Flow version for linting.');
114-
return '999.999.999';
149+
return ULTIMATE_LATEST_SEMVER;
115150
}
116151
throw e;
117152
}
@@ -133,8 +168,8 @@ function getFlowVersionFromContext(context) {
133168
} else {
134169
throw 'Could not retrieve flowVersion from settings'; // eslint-disable-line no-throw-literal
135170
}
136-
confVer = /^[0-9]+\.[0-9]+$/.test(confVer) ? `${confVer}.0` : confVer;
137-
const result = semver.coerce(confVer.split('.').map((part) => Number(part)).join('.'));
171+
172+
const result = convertConfVerToSemver(confVer);
138173
if (!result) {
139174
error(`Warning: Flow version specified in eslint-plugin-react-settings must be a valid semver version, or "detect"; got “${confVer}”`);
140175
}
@@ -158,4 +193,5 @@ module.exports = {
158193
testFlowVersion,
159194
resetWarningFlag,
160195
resetDetectedVersion,
196+
resetDefaultVersion,
161197
};

tests/util/version.js

+28
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ describe('Version', () => {
1414
expectedErrorArgs = [];
1515
versionUtil.resetWarningFlag();
1616
versionUtil.resetDetectedVersion();
17+
versionUtil.resetDefaultVersion();
1718
});
1819

1920
afterEach(() => {
@@ -65,6 +66,33 @@ describe('Version', () => {
6566
];
6667
});
6768

69+
it('uses default version from settings if provided and react is not installed', () => {
70+
context.settings.react.defaultVersion = '16.14.0';
71+
sinon.stub(context, 'getFilename').callsFake(() => path.resolve(base, 'detect-version-missing', 'test.js'));
72+
73+
assert.equal(versionUtil.testReactVersion(context, '16.14.0'), true);
74+
75+
expectedErrorArgs = [
76+
['Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming default React version for linting: "16.14.0".'],
77+
];
78+
79+
delete context.settings.react.defaultVersion;
80+
});
81+
82+
it('fails nicely with an invalid default version of react', () => {
83+
context.settings.react.defaultVersion = 'not semver';
84+
sinon.stub(context, 'getFilename').callsFake(() => path.resolve(base, 'detect-version-missing', 'test.js'));
85+
86+
assert.equal(versionUtil.testReactVersion(context, '999.999.999'), true);
87+
88+
expectedErrorArgs = [
89+
['Warning: React version specified in eslint-plugin-react-settings must be a valid semver version, or "detect"; got “not semver”. Falling back to latest version as default.'],
90+
['Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.'],
91+
];
92+
93+
delete context.settings.react.defaultVersion;
94+
});
95+
6896
it('warns only once for failure to detect react ', () => {
6997
sinon.stub(context, 'getFilename').callsFake(() => path.resolve(base, 'detect-version-missing', 'test.js'));
7098

0 commit comments

Comments
 (0)