Skip to content

Commit 59fc1b0

Browse files
committed
Init command
1 parent 938a9c5 commit 59fc1b0

File tree

10 files changed

+179
-4
lines changed

10 files changed

+179
-4
lines changed

docs/man_pages/project/creation/create.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,12 @@ Creates a new project for native development with NativeScript from the default
1616
* `<App Name>` is the name of project. The specified name must meet the requirements of all platforms that you want to target. <% if(isConsole) { %>For more information about the `<App Name>` requirements, run `$ tns help create`<% } %><% if(isHtml) { %>For projects that target Android, you can use uppercase or lowercase letters, numbers, and underscores. The name must start with a letter.
1717
For projects that target iOS, you can use uppercase or lowercase letters, numbers, and hyphens.<% } %>
1818
* `<App ID>` is the application identifier for your project. It must be a domain name in reverse and must meet the requirements of all platforms that you want to target. If not specified, the application identifier is set to `org.nativescript.<App name>` <% if(isConsole) { %>For more information about the `<App ID>` requirements, run `$ tns help create`<% } %><% if(isHtml) { %>For projects that target Android, you can use uppercase or lowercase letters, numbers, and underscores in the strings of the reversed domain name, separated by a dot. Strings must be separated by a dot and must start with a letter. For example: `com.nativescript.My_Andro1d_App`
19-
For projects that target iOS, you can use uppercase or lowercase letters, numbers, and hyphens in the strings of the reversed domain name. Strings must be separated by a dot. For example: `com.nativescript.My-i0s-App`.<% } %>
19+
For projects that target iOS, you can use uppercase or lowercase letters, numbers, and hyphens in the strings of the reversed domain name. Strings must be separated by a dot. For example: `com.nativescript.My-i0s-App`.<% } %>
20+
21+
<% if(isHtml) { %>
22+
### Related Commands
23+
24+
Command | Description
25+
----------|----------
26+
[init](init.html) | Initializes a project for development. The command prompts you to provide your project configuration interactively and uses the information to create a new package.json file or update the existing one.
27+
<% } %>
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
init
2+
==========
3+
4+
Usage | Synopsis
5+
---|---
6+
General | `$ tns init [--path <Directory>] [--force]`
7+
8+
Initializes a project for development. The command prompts you to provide your project configuration interactively and uses the information to create a new `package.json` file or update the existing one.
9+
10+
### Options
11+
* `--path` - Specifies the directory where you want to initialize the project, if different from the current directory. The directory must be empty.
12+
* `--force` - If set, applies the default project configuration and does not show the interactive prompt. The default project configuration targets the latest official runtimes and sets `org.nativescript.<folder_name>` for application identifier.
13+
14+
<% if(isHtml) { %>
15+
### Related Commands
16+
17+
Command | Description
18+
----------|----------
19+
[create](create.html) | Creates a new project for native development with NativeScript from the default template or from an existing NativeScript project.
20+
<% } %>

lib/bootstrap.ts

+3
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,7 @@ $injector.requireCommand("plugin|add", "./commands/plugin/add-plugin");
6161
$injector.requireCommand("plugin|remove", "./commands/plugin/remove-plugin");
6262
$injector.requireCommand("install", "./commands/install");
6363

64+
$injector.require("initService", "./services/init-service");
65+
$injector.requireCommand("init", "./commands/init");
66+
6467
$injector.require("projectFilesManager", "./services/project-files-manager");

lib/commands/init.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
4+
import Future = require("fibers/future");
5+
6+
export class InitCommand implements ICommand {
7+
constructor(private $initService: IInitService) { }
8+
9+
public allowedParameters: ICommandParameter[] = [];
10+
public enableHooks = false;
11+
12+
public execute(args: string[]): IFuture<void> {
13+
return this.$initService.initialize();
14+
}
15+
}
16+
$injector.registerCommand("init", InitCommand);

lib/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export var NATIVESCRIPT_KEY_NAME = "nativescript";
77
export var NODE_MODULES_FOLDER_NAME = "node_modules";
88
export var PACKAGE_JSON_FILE_NAME = "package.json";
99
export var NODE_MODULE_CACHE_PATH_KEY_NAME = "node-modules-cache-path";
10+
export var DEFAULT_APP_IDENTIFIER_PREFIX = "org.nativescript";
1011

1112
export class ReleaseType {
1213
static MAJOR = "major";

lib/declarations.ts

+6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ interface IOpener {
5050

5151
interface IOptions extends ICommonOptions {
5252
frameworkPath: string;
53+
frameworkName: string;
54+
frameworkVersion: string;
5355
copyFrom: string;
5456
linkTo: string;
5557
release: boolean;
@@ -67,4 +69,8 @@ interface IOptions extends ICommonOptions {
6769

6870
interface IProjectFilesManager {
6971
processPlatformSpecificFiles(directoryPath: string, platform: string, excludedDirs?: string[]): IFuture<void>;
72+
}
73+
74+
interface IInitService {
75+
initialize(): IFuture<void>;
7076
}

lib/options.ts

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export class Options extends commonOptionsLibPath.OptionsBase {
1313
$hostInfo: IHostInfo) {
1414
super({
1515
frameworkPath: { type: OptionType.String },
16+
frameworkName: { type: OptionType.String },
17+
frameworkVersion: { type: OptionType.String },
1618
copyFrom: { type: OptionType.String },
1719
linkTo: { type: OptionType.String },
1820
release: { type: OptionType.Boolean },

lib/services/init-service.ts

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
4+
import constants = require("./../constants");
5+
import helpers = require("./../common/helpers");
6+
import path = require("path");
7+
import semver = require("semver");
8+
9+
export class InitService implements IInitService {
10+
private static MIN_SUPPORTED_FRAMEWORK_VERSIONS: IStringDictionary = {
11+
"tns-ios": "1.1.0",
12+
"tns-android": "1.1.0"
13+
};
14+
15+
private _projectFilePath: string;
16+
17+
constructor(private $fs: IFileSystem,
18+
private $errors: IErrors,
19+
private $logger: ILogger,
20+
private $options: IOptions,
21+
private $injector: IInjector,
22+
private $staticConfig: IStaticConfig,
23+
private $projectHelper: IProjectHelper,
24+
private $prompter: IPrompter,
25+
private $npm: INodePackageManager,
26+
private $npmInstallationManager: INpmInstallationManager) { }
27+
28+
public initialize(): IFuture<void> {
29+
return (() => {
30+
let projectData: any = { };
31+
32+
if(this.$fs.exists(this.projectFilePath).wait()) {
33+
projectData = this.$fs.readJson(this.projectFilePath).wait();
34+
}
35+
36+
let projectDataBackup = _.extend({}, projectData);
37+
38+
if(!projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]) {
39+
projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = { };
40+
this.$fs.writeJson(this.projectFilePath, projectData).wait(); // We need to create package.json file here in order to prevent "No project found at or above and neither was a --path specified." when resolving platformsData
41+
}
42+
43+
try {
44+
45+
projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]["id"] = this.getProjectId().wait();
46+
47+
if(this.$options.frameworkName && this.$options.frameworkVersion) {
48+
projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][this.$options.frameworkName] = this.buildVersionData(this.$options.frameworkVersion);
49+
} else {
50+
let $platformsData = this.$injector.resolve("platformsData");
51+
_.each($platformsData.platformsNames, platform => {
52+
let platformData: IPlatformData = $platformsData.getPlatformData(platform);
53+
if(!platformData.targetedOS || (platformData.targetedOS && _.contains(platformData.targetedOS, process.platform))) {
54+
projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][platformData.frameworkPackageName] = this.getVersionData(platformData.frameworkPackageName).wait();
55+
}
56+
});
57+
}
58+
59+
this.$fs.writeJson(this.projectFilePath, projectData).wait();
60+
} catch(err) {
61+
this.$fs.writeJson(this.projectFilePath, projectDataBackup).wait();
62+
throw err;
63+
}
64+
65+
this.$logger.out("Project successfully initialized.");
66+
}).future<void>()();
67+
}
68+
69+
private get projectFilePath(): string {
70+
if(!this._projectFilePath) {
71+
let projectDir = path.resolve(this.$options.path || ".");
72+
this._projectFilePath = path.join(projectDir, constants.PACKAGE_JSON_FILE_NAME);
73+
}
74+
75+
return this._projectFilePath;
76+
}
77+
78+
private getProjectId(): IFuture<string> {
79+
return (() => {
80+
if(this.$options.appid) {
81+
return this.$options.appid;
82+
}
83+
84+
let defaultAppId = this.$projectHelper.generateDefaultAppId(path.basename(path.dirname(this.projectFilePath)), constants.DEFAULT_APP_IDENTIFIER_PREFIX);
85+
if(this.useDefaultValue) {
86+
return defaultAppId;
87+
}
88+
89+
return this.$prompter.getString("Id:", () => defaultAppId).wait();
90+
}).future<string>()();
91+
}
92+
93+
private getVersionData(packageName: string): IFuture<IStringDictionary> {
94+
return (() => {
95+
let latestVersion = this.$npmInstallationManager.getLatestVersion(packageName).wait();
96+
if(this.useDefaultValue) {
97+
return this.buildVersionData(latestVersion);
98+
}
99+
100+
let data = this.$npm.view(packageName, "versions").wait();
101+
let versions = _.filter(data[latestVersion].versions, (version: string) => semver.gte(version, InitService.MIN_SUPPORTED_FRAMEWORK_VERSIONS[packageName]));
102+
if(versions.length === 1) {
103+
this.$logger.info(`Only ${versions[0]} version is available for ${packageName} framework.`);
104+
return this.buildVersionData(versions[0]);
105+
}
106+
let sortedVersions = versions.sort(helpers.versionCompare).reverse();
107+
let version = this.$prompter.promptForChoice(`${packageName} version:`, sortedVersions).wait();
108+
return this.buildVersionData(version);
109+
}).future<IStringDictionary>()();
110+
}
111+
112+
private buildVersionData(version: string): IStringDictionary {
113+
return { "version": version };
114+
}
115+
116+
private get useDefaultValue(): boolean {
117+
return !helpers.isInteractive() || this.$options.force;
118+
}
119+
}
120+
$injector.register("initService", InitService);

lib/services/project-service.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import shell = require("shelljs");
99
import util = require("util");
1010

1111
export class ProjectService implements IProjectService {
12-
private static DEFAULT_APP_IDENTIFIER_PREFIX = "org.nativescript";
1312

1413
constructor(private $errors: IErrors,
1514
private $fs: IFileSystem,
@@ -27,7 +26,7 @@ export class ProjectService implements IProjectService {
2726
}
2827
this.$projectNameValidator.validate(projectName);
2928

30-
var projectId = this.$options.appid || this.$projectHelper.generateDefaultAppId(projectName, ProjectService.DEFAULT_APP_IDENTIFIER_PREFIX);
29+
var projectId = this.$options.appid || this.$projectHelper.generateDefaultAppId(projectName, constants.DEFAULT_APP_IDENTIFIER_PREFIX);
3130

3231
var projectDir = path.join(path.resolve(this.$options.path || "."), projectName);
3332
this.$fs.createDirectory(projectDir).wait();

0 commit comments

Comments
 (0)