Skip to content

Commit 30eaab4

Browse files
authored
Minor refactors in create-react-app (#8178)
- Remove templates version minimum stopgap. - Replace indexOf with more idiomatic alternatives. - Inline errorLogFilePatterns. - Alphabetize validFiles. - Simplify log file removal code. - Move unconditional console.log() call outside of isSafe. - Differentiate conflicting directories from files. - Document yarn version special case. - Inline printValidationResults. - Standardize checkAppName output on failure. - Add link for checkThatNpmCanReadCwd. Functionally the code should be exactly the same.
1 parent 1a13b59 commit 30eaab4

File tree

1 file changed

+69
-58
lines changed

1 file changed

+69
-58
lines changed

packages/create-react-app/createReactApp.js

+69-58
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ const validateProjectName = require('validate-npm-package-name');
5353

5454
const packageJson = require('./package.json');
5555

56-
// These files should be allowed to remain on a failed install,
57-
// but then silently removed during the next create.
58-
const errorLogFilePatterns = [
59-
'npm-debug.log',
60-
'yarn-error.log',
61-
'yarn-debug.log',
62-
];
63-
6456
let projectName;
6557

6658
const program = new commander.Command(packageJson.name)
@@ -192,14 +184,6 @@ if (typeof projectName === 'undefined') {
192184
process.exit(1);
193185
}
194186

195-
function printValidationResults(results) {
196-
if (typeof results !== 'undefined') {
197-
results.forEach(error => {
198-
console.error(chalk.red(` * ${error}`));
199-
});
200-
}
201-
}
202-
203187
createApp(
204188
projectName,
205189
program.verbose,
@@ -247,6 +231,7 @@ function createApp(
247231
if (!isSafeToCreateProjectIn(root, name)) {
248232
process.exit(1);
249233
}
234+
console.log();
250235

251236
console.log(`Creating a new React app in ${chalk.green(root)}.`);
252237
console.log();
@@ -448,10 +433,7 @@ function run(
448433
.then(({ isOnline, packageInfo, templateInfo }) => {
449434
let packageVersion = semver.coerce(packageInfo.version);
450435

451-
// This environment variable can be removed post-release.
452-
const templatesVersionMinimum = process.env.CRA_INTERNAL_TEST
453-
? '3.2.0'
454-
: '3.3.0';
436+
const templatesVersionMinimum = '3.3.0';
455437

456438
// Assume compatibility if we can't test the version.
457439
if (!semver.valid(packageVersion)) {
@@ -591,7 +573,7 @@ function getInstallPackage(version, originalDirectory) {
591573
if (validSemver) {
592574
packageToInstall += `@${validSemver}`;
593575
} else if (version) {
594-
if (version[0] === '@' && version.indexOf('/') === -1) {
576+
if (version[0] === '@' && !version.includes('/')) {
595577
packageToInstall += version;
596578
} else if (version.match(/^file:/)) {
597579
packageToInstall = `file:${path.resolve(
@@ -743,7 +725,7 @@ function getPackageInfo(installPackage) {
743725
);
744726
return Promise.resolve({ name: assumedProjectName });
745727
});
746-
} else if (installPackage.indexOf('git+') === 0) {
728+
} else if (installPackage.startsWith('git+')) {
747729
// Pull package name out of git urls e.g:
748730
// git+https://github.com/mycompany/react-scripts.git
749731
// git+ssh://github.com/mycompany/react-scripts.git#v1.2.3
@@ -785,17 +767,25 @@ function checkNpmVersion() {
785767
}
786768

787769
function checkYarnVersion() {
770+
const minYarnPnp = '1.12.0';
788771
let hasMinYarnPnp = false;
789772
let yarnVersion = null;
790773
try {
791774
yarnVersion = execSync('yarnpkg --version')
792775
.toString()
793776
.trim();
794-
let trimmedYarnVersion = /^(.+?)[-+].+$/.exec(yarnVersion);
795-
if (trimmedYarnVersion) {
796-
trimmedYarnVersion = trimmedYarnVersion.pop();
777+
if (semver.valid(yarnVersion)) {
778+
hasMinYarnPnp = semver.gte(yarnVersion, minYarnPnp);
779+
} else {
780+
// Handle non-semver compliant yarn version strings, which yarn currently
781+
// uses for nightly builds. The regex truncates anything after the first
782+
// dash. See #5362.
783+
const trimmedYarnVersionMatch = /^(.+?)[-+].+$/.exec(yarnVersion);
784+
if (trimmedYarnVersionMatch) {
785+
const trimmedYarnVersion = trimmedYarnVersionMatch.pop();
786+
hasMinYarnPnp = semver.gte(trimmedYarnVersion, minYarnPnp);
787+
}
797788
}
798-
hasMinYarnPnp = semver.gte(trimmedYarnVersion || yarnVersion, '1.12.0');
799789
} catch (err) {
800790
// ignore
801791
}
@@ -840,22 +830,29 @@ function checkAppName(appName) {
840830
const validationResult = validateProjectName(appName);
841831
if (!validationResult.validForNewPackages) {
842832
console.error(
843-
`Could not create a project called ${chalk.red(
844-
`"${appName}"`
845-
)} because of npm naming restrictions:`
833+
chalk.red(
834+
`Cannot create a project named ${chalk.green(
835+
`"${appName}"`
836+
)} because of npm naming restrictions:\n`
837+
)
846838
);
847-
printValidationResults(validationResult.errors);
848-
printValidationResults(validationResult.warnings);
839+
[
840+
...(validationResult.errors || []),
841+
...(validationResult.warnings || []),
842+
].forEach(error => {
843+
console.error(chalk.red(` * ${error}`));
844+
});
845+
console.error(chalk.red('\nPlease choose a different project name.'));
849846
process.exit(1);
850847
}
851848

852849
// TODO: there should be a single place that holds the dependencies
853850
const dependencies = ['react', 'react-dom', 'react-scripts'].sort();
854-
if (dependencies.indexOf(appName) >= 0) {
851+
if (dependencies.includes(appName)) {
855852
console.error(
856853
chalk.red(
857-
`We cannot create a project called ${chalk.green(
858-
appName
854+
`Cannot create a project named ${chalk.green(
855+
`"${appName}"`
859856
)} because a dependency with the same name exists.\n` +
860857
`Due to the way npm works, the following names are not allowed:\n\n`
861858
) +
@@ -917,41 +914,57 @@ function setCaretRangeForRuntimeDeps(packageName) {
917914
function isSafeToCreateProjectIn(root, name) {
918915
const validFiles = [
919916
'.DS_Store',
920-
'Thumbs.db',
921917
'.git',
918+
'.gitattributes',
922919
'.gitignore',
923-
'.idea',
924-
'README.md',
925-
'LICENSE',
920+
'.gitlab-ci.yml',
926921
'.hg',
927-
'.hgignore',
928922
'.hgcheck',
923+
'.hgignore',
924+
'.idea',
929925
'.npmignore',
930-
'mkdocs.yml',
931-
'docs',
932926
'.travis.yml',
933-
'.gitlab-ci.yml',
934-
'.gitattributes',
927+
'docs',
928+
'LICENSE',
929+
'README.md',
930+
'mkdocs.yml',
931+
'Thumbs.db',
935932
];
936-
console.log();
933+
// These files should be allowed to remain on a failed install, but then
934+
// silently removed during the next create.
935+
const errorLogFilePatterns = [
936+
'npm-debug.log',
937+
'yarn-error.log',
938+
'yarn-debug.log',
939+
];
940+
const isErrorLog = file => {
941+
return errorLogFilePatterns.some(pattern => file.startsWith(pattern));
942+
};
937943

938944
const conflicts = fs
939945
.readdirSync(root)
940946
.filter(file => !validFiles.includes(file))
941947
// IntelliJ IDEA creates module files before CRA is launched
942948
.filter(file => !/\.iml$/.test(file))
943949
// Don't treat log files from previous installation as conflicts
944-
.filter(
945-
file => !errorLogFilePatterns.some(pattern => file.indexOf(pattern) === 0)
946-
);
950+
.filter(file => !isErrorLog(file));
947951

948952
if (conflicts.length > 0) {
949953
console.log(
950954
`The directory ${chalk.green(name)} contains files that could conflict:`
951955
);
952956
console.log();
953957
for (const file of conflicts) {
954-
console.log(` ${file}`);
958+
try {
959+
const stats = fs.lstatSync(path.join(root, file));
960+
if (stats.isDirectory()) {
961+
console.log(` ${chalk.blue(`${file}/`)}`);
962+
} else {
963+
console.log(` ${file}`);
964+
}
965+
} catch (e) {
966+
console.log(` ${file}`);
967+
}
955968
}
956969
console.log();
957970
console.log(
@@ -961,15 +974,11 @@ function isSafeToCreateProjectIn(root, name) {
961974
return false;
962975
}
963976

964-
// Remove any remnant files from a previous installation
965-
const currentFiles = fs.readdirSync(path.join(root));
966-
currentFiles.forEach(file => {
967-
errorLogFilePatterns.forEach(errorLogFilePattern => {
968-
// This will catch `(npm-debug|yarn-error|yarn-debug).log*` files
969-
if (file.indexOf(errorLogFilePattern) === 0) {
970-
fs.removeSync(path.join(root, file));
971-
}
972-
});
977+
// Remove any log files from a previous installation.
978+
fs.readdirSync(root).forEach(file => {
979+
if (isErrorLog(file)) {
980+
fs.removeSync(path.join(root, file));
981+
}
973982
});
974983
return true;
975984
}
@@ -989,6 +998,8 @@ function getProxy() {
989998
}
990999
}
9911000
}
1001+
1002+
// See https://github.com/facebook/create-react-app/pull/3355
9921003
function checkThatNpmCanReadCwd() {
9931004
const cwd = process.cwd();
9941005
let childOutput = null;
@@ -1013,7 +1024,7 @@ function checkThatNpmCanReadCwd() {
10131024
// "; cwd = C:\path\to\current\dir" (unquoted)
10141025
// I couldn't find an easier way to get it.
10151026
const prefix = '; cwd = ';
1016-
const line = lines.find(line => line.indexOf(prefix) === 0);
1027+
const line = lines.find(line => line.startsWith(prefix));
10171028
if (typeof line !== 'string') {
10181029
// Fail gracefully. They could remove it.
10191030
return true;

0 commit comments

Comments
 (0)