@@ -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 )
@@ -156,6 +148,10 @@ const program = new commander.Command(packageJson.name)
156148
157149if ( program . info ) {
158150 console . log ( chalk . bold ( '\nEnvironment Info:' ) ) ;
151+ console . log (
152+ `\n current version of ${ packageJson . name } : ${ packageJson . version } `
153+ ) ;
154+ console . log ( ` running from ${ __dirname } ` ) ;
159155 return envinfo
160156 . run (
161157 {
@@ -188,14 +184,6 @@ if (typeof projectName === 'undefined') {
188184 process . exit ( 1 ) ;
189185}
190186
191- function printValidationResults ( results ) {
192- if ( typeof results !== 'undefined' ) {
193- results . forEach ( error => {
194- console . error ( chalk . red ( ` * ${ error } ` ) ) ;
195- } ) ;
196- }
197- }
198-
199187createApp (
200188 projectName ,
201189 program . verbose ,
@@ -243,6 +231,7 @@ function createApp(
243231 if ( ! isSafeToCreateProjectIn ( root , name ) ) {
244232 process . exit ( 1 ) ;
245233 }
234+ console . log ( ) ;
246235
247236 console . log ( `Creating a new React app in ${ chalk . green ( root ) } .` ) ;
248237 console . log ( ) ;
@@ -444,10 +433,7 @@ function run(
444433 . then ( ( { isOnline, packageInfo, templateInfo } ) => {
445434 let packageVersion = semver . coerce ( packageInfo . version ) ;
446435
447- // This environment variable can be removed post-release.
448- const templatesVersionMinimum = process . env . CRA_INTERNAL_TEST
449- ? '3.2.0'
450- : '3.3.0' ;
436+ const templatesVersionMinimum = '3.3.0' ;
451437
452438 // Assume compatibility if we can't test the version.
453439 if ( ! semver . valid ( packageVersion ) ) {
@@ -587,7 +573,7 @@ function getInstallPackage(version, originalDirectory) {
587573 if ( validSemver ) {
588574 packageToInstall += `@${ validSemver } ` ;
589575 } else if ( version ) {
590- if ( version [ 0 ] === '@' && version . indexOf ( '/' ) === - 1 ) {
576+ if ( version [ 0 ] === '@' && ! version . includes ( '/' ) ) {
591577 packageToInstall += version ;
592578 } else if ( version . match ( / ^ f i l e : / ) ) {
593579 packageToInstall = `file:${ path . resolve (
@@ -654,10 +640,25 @@ function getTemplateInstallPackage(template, originalDirectory) {
654640 const scope = packageMatch [ 1 ] || '' ;
655641 const templateName = packageMatch [ 2 ] ;
656642
657- const name = templateName . startsWith ( templateToInstall )
658- ? templateName
659- : `${ templateToInstall } -${ templateName } ` ;
660- templateToInstall = `${ scope } ${ name } ` ;
643+ if (
644+ templateName === templateToInstall ||
645+ templateName . startsWith ( `${ templateToInstall } -` )
646+ ) {
647+ // Covers:
648+ // - cra-template
649+ // - @SCOPE/cra-template
650+ // - cra-template-NAME
651+ // - @SCOPE/cra-template-NAME
652+ templateToInstall = `${ scope } ${ templateName } ` ;
653+ } else if ( templateName . startsWith ( '@' ) ) {
654+ // Covers using @SCOPE only
655+ templateToInstall = `${ templateName } /${ templateToInstall } ` ;
656+ } else {
657+ // Covers templates without the `cra-template` prefix:
658+ // - NAME
659+ // - @SCOPE/NAME
660+ templateToInstall = `${ scope } ${ templateToInstall } -${ templateName } ` ;
661+ }
661662 }
662663 }
663664
@@ -739,7 +740,7 @@ function getPackageInfo(installPackage) {
739740 ) ;
740741 return Promise . resolve ( { name : assumedProjectName } ) ;
741742 } ) ;
742- } else if ( installPackage . indexOf ( 'git+' ) === 0 ) {
743+ } else if ( installPackage . startsWith ( 'git+' ) ) {
743744 // Pull package name out of git urls e.g:
744745 // git+https://github.com/mycompany/react-scripts.git
745746 // git+ssh://github.com/mycompany/react-scripts.git#v1.2.3
@@ -781,17 +782,25 @@ function checkNpmVersion() {
781782}
782783
783784function checkYarnVersion ( ) {
785+ const minYarnPnp = '1.12.0' ;
784786 let hasMinYarnPnp = false ;
785787 let yarnVersion = null ;
786788 try {
787789 yarnVersion = execSync ( 'yarnpkg --version' )
788790 . toString ( )
789791 . trim ( ) ;
790- let trimmedYarnVersion = / ^ ( .+ ?) [ - + ] .+ $ / . exec ( yarnVersion ) ;
791- if ( trimmedYarnVersion ) {
792- trimmedYarnVersion = trimmedYarnVersion . pop ( ) ;
792+ if ( semver . valid ( yarnVersion ) ) {
793+ hasMinYarnPnp = semver . gte ( yarnVersion , minYarnPnp ) ;
794+ } else {
795+ // Handle non-semver compliant yarn version strings, which yarn currently
796+ // uses for nightly builds. The regex truncates anything after the first
797+ // dash. See #5362.
798+ const trimmedYarnVersionMatch = / ^ ( .+ ?) [ - + ] .+ $ / . exec ( yarnVersion ) ;
799+ if ( trimmedYarnVersionMatch ) {
800+ const trimmedYarnVersion = trimmedYarnVersionMatch . pop ( ) ;
801+ hasMinYarnPnp = semver . gte ( trimmedYarnVersion , minYarnPnp ) ;
802+ }
793803 }
794- hasMinYarnPnp = semver . gte ( trimmedYarnVersion || yarnVersion , '1.12.0' ) ;
795804 } catch ( err ) {
796805 // ignore
797806 }
@@ -836,22 +845,29 @@ function checkAppName(appName) {
836845 const validationResult = validateProjectName ( appName ) ;
837846 if ( ! validationResult . validForNewPackages ) {
838847 console . error (
839- `Could not create a project called ${ chalk . red (
840- `"${ appName } "`
841- ) } because of npm naming restrictions:`
848+ chalk . red (
849+ `Cannot create a project named ${ chalk . green (
850+ `"${ appName } "`
851+ ) } because of npm naming restrictions:\n`
852+ )
842853 ) ;
843- printValidationResults ( validationResult . errors ) ;
844- printValidationResults ( validationResult . warnings ) ;
854+ [
855+ ...( validationResult . errors || [ ] ) ,
856+ ...( validationResult . warnings || [ ] ) ,
857+ ] . forEach ( error => {
858+ console . error ( chalk . red ( ` * ${ error } ` ) ) ;
859+ } ) ;
860+ console . error ( chalk . red ( '\nPlease choose a different project name.' ) ) ;
845861 process . exit ( 1 ) ;
846862 }
847863
848864 // TODO: there should be a single place that holds the dependencies
849865 const dependencies = [ 'react' , 'react-dom' , 'react-scripts' ] . sort ( ) ;
850- if ( dependencies . indexOf ( appName ) >= 0 ) {
866+ if ( dependencies . includes ( appName ) ) {
851867 console . error (
852868 chalk . red (
853- `We cannot create a project called ${ chalk . green (
854- appName
869+ `Cannot create a project named ${ chalk . green (
870+ `" ${ appName } "`
855871 ) } because a dependency with the same name exists.\n` +
856872 `Due to the way npm works, the following names are not allowed:\n\n`
857873 ) +
@@ -913,41 +929,57 @@ function setCaretRangeForRuntimeDeps(packageName) {
913929function isSafeToCreateProjectIn ( root , name ) {
914930 const validFiles = [
915931 '.DS_Store' ,
916- 'Thumbs.db' ,
917932 '.git' ,
933+ '.gitattributes' ,
918934 '.gitignore' ,
919- '.idea' ,
920- 'README.md' ,
921- 'LICENSE' ,
935+ '.gitlab-ci.yml' ,
922936 '.hg' ,
923- '.hgignore' ,
924937 '.hgcheck' ,
938+ '.hgignore' ,
939+ '.idea' ,
925940 '.npmignore' ,
926- 'mkdocs.yml' ,
927- 'docs' ,
928941 '.travis.yml' ,
929- '.gitlab-ci.yml' ,
930- '.gitattributes' ,
942+ 'docs' ,
943+ 'LICENSE' ,
944+ 'README.md' ,
945+ 'mkdocs.yml' ,
946+ 'Thumbs.db' ,
931947 ] ;
932- console . log ( ) ;
948+ // These files should be allowed to remain on a failed install, but then
949+ // silently removed during the next create.
950+ const errorLogFilePatterns = [
951+ 'npm-debug.log' ,
952+ 'yarn-error.log' ,
953+ 'yarn-debug.log' ,
954+ ] ;
955+ const isErrorLog = file => {
956+ return errorLogFilePatterns . some ( pattern => file . startsWith ( pattern ) ) ;
957+ } ;
933958
934959 const conflicts = fs
935960 . readdirSync ( root )
936961 . filter ( file => ! validFiles . includes ( file ) )
937962 // IntelliJ IDEA creates module files before CRA is launched
938963 . filter ( file => ! / \. i m l $ / . test ( file ) )
939964 // Don't treat log files from previous installation as conflicts
940- . filter (
941- file => ! errorLogFilePatterns . some ( pattern => file . indexOf ( pattern ) === 0 )
942- ) ;
965+ . filter ( file => ! isErrorLog ( file ) ) ;
943966
944967 if ( conflicts . length > 0 ) {
945968 console . log (
946969 `The directory ${ chalk . green ( name ) } contains files that could conflict:`
947970 ) ;
948971 console . log ( ) ;
949972 for ( const file of conflicts ) {
950- console . log ( ` ${ file } ` ) ;
973+ try {
974+ const stats = fs . lstatSync ( path . join ( root , file ) ) ;
975+ if ( stats . isDirectory ( ) ) {
976+ console . log ( ` ${ chalk . blue ( `${ file } /` ) } ` ) ;
977+ } else {
978+ console . log ( ` ${ file } ` ) ;
979+ }
980+ } catch ( e ) {
981+ console . log ( ` ${ file } ` ) ;
982+ }
951983 }
952984 console . log ( ) ;
953985 console . log (
@@ -957,15 +989,11 @@ function isSafeToCreateProjectIn(root, name) {
957989 return false ;
958990 }
959991
960- // Remove any remnant files from a previous installation
961- const currentFiles = fs . readdirSync ( path . join ( root ) ) ;
962- currentFiles . forEach ( file => {
963- errorLogFilePatterns . forEach ( errorLogFilePattern => {
964- // This will catch `(npm-debug|yarn-error|yarn-debug).log*` files
965- if ( file . indexOf ( errorLogFilePattern ) === 0 ) {
966- fs . removeSync ( path . join ( root , file ) ) ;
967- }
968- } ) ;
992+ // Remove any log files from a previous installation.
993+ fs . readdirSync ( root ) . forEach ( file => {
994+ if ( isErrorLog ( file ) ) {
995+ fs . removeSync ( path . join ( root , file ) ) ;
996+ }
969997 } ) ;
970998 return true ;
971999}
@@ -985,6 +1013,8 @@ function getProxy() {
9851013 }
9861014 }
9871015}
1016+
1017+ // See https://github.com/facebook/create-react-app/pull/3355
9881018function checkThatNpmCanReadCwd ( ) {
9891019 const cwd = process . cwd ( ) ;
9901020 let childOutput = null ;
@@ -1009,7 +1039,7 @@ function checkThatNpmCanReadCwd() {
10091039 // "; cwd = C:\path\to\current\dir" (unquoted)
10101040 // I couldn't find an easier way to get it.
10111041 const prefix = '; cwd = ' ;
1012- const line = lines . find ( line => line . indexOf ( prefix ) === 0 ) ;
1042+ const line = lines . find ( line => line . startsWith ( prefix ) ) ;
10131043 if ( typeof line !== 'string' ) {
10141044 // Fail gracefully. They could remove it.
10151045 return true ;
0 commit comments