44import * as constants from "../constants" ;
55import * as osenv from "osenv" ;
66import * as path from "path" ;
7- import * as shell from "shelljs" ;
7+ import * as shelljs from "shelljs" ;
88
99export class ProjectService implements IProjectService {
1010
@@ -18,7 +18,7 @@ export class ProjectService implements IProjectService {
1818 private $projectTemplatesService : IProjectTemplatesService ,
1919 private $options : IOptions ) { }
2020
21- public createProject ( projectName : string ) : IFuture < void > {
21+ public createProject ( projectName : string , selectedTemplate ?: string ) : IFuture < void > {
2222 return ( ( ) => {
2323 if ( ! projectName ) {
2424 this . $errors . fail ( "You must specify <App name> when creating a new project." ) ;
@@ -51,7 +51,6 @@ export class ProjectService implements IProjectService {
5151
5252 let appDirectory = path . join ( projectDir , constants . APP_FOLDER_NAME ) ;
5353 let appPath : string = null ;
54-
5554 if ( customAppPath ) {
5655 this . $logger . trace ( "Using custom app from %s" , customAppPath ) ;
5756
@@ -68,25 +67,77 @@ export class ProjectService implements IProjectService {
6867 this . $logger . trace ( "Copying custom app into %s" , appDirectory ) ;
6968 appPath = customAppPath ;
7069 } else {
71- // No custom app - use nativescript hello world application
72- this . $logger . trace ( "Using NativeScript hello world application" ) ;
73- let defaultTemplatePath = this . $projectTemplatesService . defaultTemplatePath . wait ( ) ;
74- this . $logger . trace ( "Copying NativeScript hello world application into %s" , appDirectory ) ;
70+ let defaultTemplatePath = this . $projectTemplatesService . prepareTemplate ( selectedTemplate ) . wait ( ) ;
71+ this . $logger . trace ( `Copying application from '${ defaultTemplatePath } ' into '${ appDirectory } '.` ) ;
7572 appPath = defaultTemplatePath ;
7673 }
7774
7875 try {
7976 this . createProjectCore ( projectDir , appPath , projectId ) . wait ( ) ;
77+ //update dependencies and devDependencies of newly created project with data from template
78+ this . mergeProjectAndTemplateProperties ( projectDir , appPath ) . wait ( ) ;
79+ this . updateAppResourcesDir ( appDirectory ) . wait ( ) ;
80+ // Delete app/package.json file, its just causing confusion.
81+ // Also its dependencies and devDependencies are already merged in project's package.json.
82+ this . $fs . deleteFile ( path . join ( projectDir , constants . APP_FOLDER_NAME , constants . PACKAGE_JSON_FILE_NAME ) ) . wait ( ) ;
83+ this . $npm . install ( projectDir , projectDir , { "ignore-scripts" : this . $options . ignoreScripts } ) . wait ( ) ;
8084 } catch ( err ) {
8185 this . $fs . deleteDirectory ( projectDir ) . wait ( ) ;
8286 throw err ;
8387 }
84-
8588 this . $logger . out ( "Project %s was successfully created" , projectName ) ;
8689
8790 } ) . future < void > ( ) ( ) ;
8891 }
8992
93+ private mergeProjectAndTemplateProperties ( projectDir : string , templatePath : string ) : IFuture < void > {
94+ return ( ( ) => {
95+ let templatePackageJsonPath = path . join ( templatePath , constants . PACKAGE_JSON_FILE_NAME ) ;
96+ if ( this . $fs . exists ( templatePackageJsonPath ) . wait ( ) ) {
97+ let projectPackageJsonPath = path . join ( projectDir , constants . PACKAGE_JSON_FILE_NAME ) ;
98+ let projectPackageJsonData = this . $fs . readJson ( projectPackageJsonPath ) . wait ( ) ;
99+ this . $logger . trace ( "Initial project package.json data: " , projectPackageJsonData ) ;
100+ let templatePackageJsonData = this . $fs . readJson ( templatePackageJsonPath ) . wait ( ) ;
101+ if ( projectPackageJsonData . dependencies || templatePackageJsonData . dependencies ) {
102+ projectPackageJsonData . dependencies = this . mergeDependencies ( projectPackageJsonData . dependencies , templatePackageJsonData . dependencies ) ;
103+ }
104+
105+ if ( projectPackageJsonData . devDependencies || templatePackageJsonData . devDependencies ) {
106+ projectPackageJsonData . devDependencies = this . mergeDependencies ( projectPackageJsonData . devDependencies , templatePackageJsonData . devDependencies ) ;
107+ }
108+
109+ this . $logger . trace ( "New project package.json data: " , projectPackageJsonData ) ;
110+ this . $fs . writeJson ( projectPackageJsonPath , projectPackageJsonData ) . wait ( ) ;
111+ } else {
112+ this . $logger . trace ( `Template ${ templatePath } does not have ${ constants . PACKAGE_JSON_FILE_NAME } file.` ) ;
113+ }
114+ } ) . future < void > ( ) ( ) ;
115+ }
116+
117+ private updateAppResourcesDir ( appDirectory : string ) : IFuture < void > {
118+ return ( ( ) => {
119+ let defaultAppResourcesDir = path . join ( this . $projectTemplatesService . defaultTemplatePath . wait ( ) , constants . APP_RESOURCES_FOLDER_NAME ) ;
120+ let targetAppResourcesDir = path . join ( appDirectory , constants . APP_RESOURCES_FOLDER_NAME ) ;
121+ this . $logger . trace ( `Updating AppResources values from ${ defaultAppResourcesDir } to ${ targetAppResourcesDir } ` ) ;
122+ shelljs . cp ( "-R" , path . join ( defaultAppResourcesDir , "*" ) , targetAppResourcesDir ) ;
123+ } ) . future < void > ( ) ( ) ;
124+ }
125+
126+ private mergeDependencies ( projectDependencies : IStringDictionary , templateDependencies : IStringDictionary ) : IStringDictionary {
127+ // Cast to any when logging as logger thinks it can print only string.
128+ // Cannot use toString() because we want to print the whole objects, not [Object object]
129+ this . $logger . trace ( "Merging dependencies, projectDependencies are: " , < any > projectDependencies , " templateDependencies are: " , < any > templateDependencies ) ;
130+ projectDependencies = projectDependencies || { } ;
131+ _ . extend ( projectDependencies , templateDependencies || { } ) ;
132+ let sortedDeps : IStringDictionary = { } ;
133+ let dependenciesNames = _ . keys ( projectDependencies ) . sort ( ) ;
134+ _ . each ( dependenciesNames , ( key : string ) => {
135+ sortedDeps [ key ] = projectDependencies [ key ] ;
136+ } ) ;
137+ this . $logger . trace ( "Sorted merged dependencies are: " , < any > sortedDeps ) ;
138+ return sortedDeps ;
139+ }
140+
90141 private createProjectCore ( projectDir : string , appSourcePath : string , projectId : string ) : IFuture < void > {
91142 return ( ( ) => {
92143 this . $fs . ensureDirectoryExists ( projectDir ) . wait ( ) ;
@@ -97,7 +148,7 @@ export class ProjectService implements IProjectService {
97148 if ( this . $options . symlink ) {
98149 this . $fs . symlink ( appSourcePath , appDestinationPath ) . wait ( ) ;
99150 } else {
100- shell . cp ( '-R' , path . join ( appSourcePath , "*" ) , appDestinationPath ) ;
151+ shelljs . cp ( '-R' , path . join ( appSourcePath , "*" ) , appDestinationPath ) ;
101152 }
102153
103154 this . createBasicProjectStructure ( projectDir , projectId ) . wait ( ) ;
0 commit comments