/** * @fileoverview Utility functions for React and Flow version configuration * @author Yannick Croissant */ 'use strict'; const resolve = require('resolve'); const error = require('./error'); let warnedForMissingVersion = false; function resetWarningFlag() { warnedForMissingVersion = false; } function detectReactVersion() { try { const reactPath = resolve.sync('react', {basedir: process.cwd()}); const react = require(reactPath); // eslint-disable-line import/no-dynamic-require return react.version; } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { if (!warnedForMissingVersion) { error('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.'); warnedForMissingVersion = true; } return '999.999.999'; } throw e; } } function getReactVersionFromContext(context) { let confVer = '999.999.999'; // .eslintrc shared settings (http://eslint.org/docs/user-guide/configuring#adding-shared-settings) if (context.settings.react && context.settings.react.version) { let settingsVersion = context.settings.react.version; if (settingsVersion === 'detect') { settingsVersion = detectReactVersion(); } if (typeof settingsVersion !== 'string') { error('Warning: React version specified in eslint-plugin-react-settings must be a string; ' + `got “${typeof settingsVersion}”`); } confVer = String(settingsVersion); } else if (!warnedForMissingVersion) { error('Warning: React version not specified in eslint-plugin-react settings. ' + 'See https://github.com/yannickcr/eslint-plugin-react#configuration .'); warnedForMissingVersion = true; } confVer = /^[0-9]+\.[0-9]+$/.test(confVer) ? `${confVer}.0` : confVer; return confVer.split('.').map(part => Number(part)); } function detectFlowVersion() { try { const flowPackageJsonPath = resolve.sync('flow-bin/package.json', {basedir: process.cwd()}); const flowPackageJson = require(flowPackageJsonPath); // eslint-disable-line import/no-dynamic-require return flowPackageJson.version; } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { error('Warning: Flow version was set to "detect" in eslint-plugin-react settings, ' + 'but the "flow-bin" package is not installed. Assuming latest Flow version for linting.'); return '999.999.999'; } throw e; } } function getFlowVersionFromContext(context) { let confVer = '999.999.999'; // .eslintrc shared settings (http://eslint.org/docs/user-guide/configuring#adding-shared-settings) if (context.settings.react && context.settings.react.flowVersion) { let flowVersion = context.settings.react.flowVersion; if (flowVersion === 'detect') { flowVersion = detectFlowVersion(); } if (typeof flowVersion !== 'string') { error('Warning: Flow version specified in eslint-plugin-react-settings must be a string; ' + `got “${typeof flowVersion}”`); } confVer = String(flowVersion); } else { throw 'Could not retrieve flowVersion from settings'; // eslint-disable-line no-throw-literal } confVer = /^[0-9]+\.[0-9]+$/.test(confVer) ? `${confVer}.0` : confVer; return confVer.split('.').map(part => Number(part)); } function normalizeParts(parts) { return Array.from({length: 3}, (_, i) => (parts[i] || 0)); } function test(context, methodVer, confVer) { const methodVers = normalizeParts(String(methodVer || '').split('.').map(part => Number(part))); const confVers = normalizeParts(confVer); const higherMajor = methodVers[0] < confVers[0]; const higherMinor = methodVers[0] === confVers[0] && methodVers[1] < confVers[1]; const higherOrEqualPatch = methodVers[0] === confVers[0] && methodVers[1] === confVers[1] && methodVers[2] <= confVers[2]; return higherMajor || higherMinor || higherOrEqualPatch; } function testReactVersion(context, methodVer) { return test(context, methodVer, getReactVersionFromContext(context)); } function testFlowVersion(context, methodVer) { return test(context, methodVer, getFlowVersionFromContext(context)); } module.exports = { testReactVersion, testFlowVersion, resetWarningFlag };