@@ -53,14 +53,6 @@ const validateProjectName = require('validate-npm-package-name');
5353
5454const 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-
6456let projectName ;
6557
6658const 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-
203187createApp (
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 ( / ^ f i l e : / ) ) {
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
787769function 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) {
917914function 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 => ! / \. i m l $ / . 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
9921003function 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