diff --git a/lib/common b/lib/common
index 3f8ec96802..c539660037 160000
--- a/lib/common
+++ b/lib/common
@@ -1 +1 @@
-Subproject commit 3f8ec96802f3ed1b518e22dc7cd4c25a595ebc3e
+Subproject commit c5396600371891c19088d022ce70b435e27324ce
diff --git a/lib/config.ts b/lib/config.ts
index 6ee2c069cc..e33d9173b6 100644
--- a/lib/config.ts
+++ b/lib/config.ts
@@ -21,7 +21,8 @@ export class Configuration extends configBaseLib.ConfigBase implements IConfigur
$injector.register("config", Configuration);
export class StaticConfig extends staticConfigBaseLibPath.StaticConfigBase implements IStaticConfig {
- public PROJECT_FILE_NAME = ".tnsproject";
+ public PROJECT_FILE_NAME = "package.json";
+ public CLIENT_NAME_KEY_IN_PROJECT_FILE = "nativescript";
public CLIENT_NAME = "tns";
public CLIENT_NAME_ALIAS = "NativeScript";
public ANALYTICS_API_KEY = "5752dabccfc54c4ab82aea9626b7338e";
diff --git a/lib/project-data.ts b/lib/project-data.ts
index ee60487504..365e74b612 100644
--- a/lib/project-data.ts
+++ b/lib/project-data.ts
@@ -1,10 +1,14 @@
///
"use strict";
+import constants = require("./constants");
import path = require("path");
import os = require("os");
+import options = require("./common/options");
export class ProjectData implements IProjectData {
+ private static OLD_PROJECT_FILE_NAME = ".tnsproject";
+
public projectDir: string;
public platformsDir: string;
public projectFilePath: string;
@@ -13,6 +17,7 @@ export class ProjectData implements IProjectData {
constructor(private $fs: IFileSystem,
private $errors: IErrors,
+ private $logger: ILogger,
private $projectHelper: IProjectHelper,
private $staticConfig: IStaticConfig) {
this.initializeProjectData().wait();
@@ -20,18 +25,16 @@ export class ProjectData implements IProjectData {
private initializeProjectData(): IFuture {
return(() => {
- var projectDir = this.$projectHelper.projectDir;
+ let projectDir = this.$projectHelper.projectDir;
// If no project found, projectDir should be null
if(projectDir) {
- this.projectDir = projectDir;
- this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
- this.platformsDir = path.join(projectDir, "platforms");
- this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
+ this.initializeProjectDataCore(projectDir);
+ let data: any = null;
if (this.$fs.exists(this.projectFilePath).wait()) {
try {
- var fileContent = this.$fs.readJson(this.projectFilePath).wait();
- this.projectId = fileContent.id;
+ let fileContent = this.$fs.readJson(this.projectFilePath).wait();
+ data = fileContent[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE];
} catch (err) {
this.$errors.fail({formatStr: "The project file %s is corrupted." + os.EOL +
"Consider restoring an earlier version from your source control or backup." + os.EOL +
@@ -39,11 +42,62 @@ export class ProjectData implements IProjectData {
suppressCommandHelp: true},
this.projectFilePath, err.toString());
}
- }
+
+ if(data) {
+ this.projectId = data.id;
+ } else { // This is the case when we have package.json file but nativescipt key is not presented in it
+ this.tryToUpgradeProject().wait();
+ }
+ }
+ } else { // This is the case when no project file found
+ this.tryToUpgradeProject().wait();
+ }
+ }).future()();
+ }
+
+ private throwNoProjectFoundError(): void {
+ this.$errors.fail("No project found at or above '%s' and neither was a --path specified.", options.path || path.resolve("."));
+ }
+
+ private tryToUpgradeProject(): IFuture {
+ return (() => {
+ let projectDir = this.projectDir || path.resolve(options.path || ".");
+ let oldProjectFilePath = path.join(projectDir, ProjectData.OLD_PROJECT_FILE_NAME);
+ if(this.$fs.exists(oldProjectFilePath).wait()) {
+ this.upgrade(projectDir, oldProjectFilePath).wait();
} else {
- this.$errors.fail("No project found at or above '%s' and neither was a --path specified.", process.cwd());
+ this.throwNoProjectFoundError();
}
}).future()();
}
+
+ private upgrade(projectDir: string, oldProjectFilePath: string): IFuture {
+ return (() => {
+ try {
+ let oldProjectData = this.$fs.readJson(oldProjectFilePath).wait();
+
+ let newProjectFilePath = this.projectFilePath || path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
+ let newProjectData = this.$fs.exists(newProjectFilePath).wait() ? this.$fs.readJson(newProjectFilePath).wait() : {};
+ newProjectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = oldProjectData;
+ this.$fs.writeJson(newProjectFilePath, newProjectData).wait();
+
+ this.$fs.deleteFile(oldProjectFilePath).wait();
+ } catch(err) {
+ this.$logger.out("An error occurred while upgrading your project.");
+ throw err;
+ }
+
+ this.initializeProjectDataCore(projectDir);
+
+ this.$logger.out("Successfully upgraded your project file.");
+ }).future()();
+ }
+
+ private initializeProjectDataCore(projectDir: string): void {
+ this.projectDir = projectDir;
+ this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
+ this.platformsDir = path.join(projectDir, "platforms");
+ this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
+ }
}
$injector.register("projectData", ProjectData);
\ No newline at end of file
diff --git a/lib/services/project-data-service.ts b/lib/services/project-data-service.ts
index c99eb1d3ef..2f6a00a837 100644
--- a/lib/services/project-data-service.ts
+++ b/lib/services/project-data-service.ts
@@ -1,48 +1,54 @@
///
"use strict";
+import constants = require("./../constants");
import path = require("path");
import assert = require("assert");
export class ProjectDataService implements IProjectDataService {
- private projectFileName: string;
+ private projectFilePath: string;
private projectData: IDictionary;
constructor(private $fs: IFileSystem,
- private $staticConfig: IStaticConfig) {
+ private $staticConfig: IStaticConfig,
+ private $errors: IErrors,
+ private $logger: ILogger) {
}
public initialize(projectDir: string): void {
- if(!this.projectFileName) {
- this.projectFileName = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
+ if(!this.projectFilePath) {
+ this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
}
}
public getValue(propertyName: string): IFuture {
return (() => {
this.loadProjectFile().wait();
- return this.projectData ? this.projectData[propertyName] : null;
+ return this.projectData ? this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][propertyName] : null;
}).future()();
}
public setValue(key: string, value: any): IFuture {
return (() => {
this.loadProjectFile().wait();
- this.projectData[key] = value;
- this.$fs.writeJson(this.projectFileName, this.projectData, "\t").wait();
+ if(!this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]) {
+ this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = Object.create(null);
+ }
+ this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][key] = value;
+ this.$fs.writeJson(this.projectFilePath, this.projectData, "\t").wait();
}).future()();
}
private loadProjectFile(): IFuture {
return (() => {
- assert.ok(this.projectFileName, "Initialize method of projectDataService is not called");
+ assert.ok(this.projectFilePath, "Initialize method of projectDataService is not called");
if(!this.projectData) {
- if(!this.$fs.exists(this.projectFileName).wait()) {
- this.$fs.writeFile(this.projectFileName, null).wait();
+ if(!this.$fs.exists(this.projectFilePath).wait()) {
+ this.$fs.writeFile(this.projectFilePath, null).wait();
}
- this.projectData = this.$fs.readJson(this.projectFileName).wait() || Object.create(null);
+ this.projectData = this.$fs.readJson(this.projectFilePath).wait() || Object.create(null);
}
}).future()();
}
diff --git a/test/project-service.ts b/test/project-service.ts
index 3042110ba1..27008d25ea 100644
--- a/test/project-service.ts
+++ b/test/project-service.ts
@@ -6,11 +6,13 @@ import stubs = require('./stubs');
import ProjectServiceLib = require("../lib/services/project-service");
import ProjectDataServiceLib = require("../lib/services/project-data-service");
+import ProjectDataLib = require("../lib/project-data");
import ProjectHelperLib = require("../lib/common/project-helper");
import StaticConfigLib = require("../lib/config");
import NpmLib = require("../lib/node-package-manager");
import HttpClientLib = require("../lib/common/http-client");
import fsLib = require("../lib/common/file-system");
+import platformServiceLib = require("../lib/services/platform-service");
import path = require("path");
import temp = require("temp");
@@ -64,7 +66,7 @@ class ProjectIntegrationTest {
var projectDir = path.join(tempFolder, projectName);
var appDirectoryPath = path.join(projectDir, "app");
var platformsDirectoryPath = path.join(projectDir, "platforms");
- var tnsProjectFilePath = path.join(projectDir, ".tnsproject");
+ let tnsProjectFilePath = path.join(projectDir, "package.json");
assert.isTrue(fs.exists(appDirectoryPath).wait());
assert.isTrue(fs.exists(platformsDirectoryPath).wait());
@@ -73,7 +75,7 @@ class ProjectIntegrationTest {
assert.isFalse(fs.isEmptyDir(appDirectoryPath).wait());
assert.isTrue(fs.isEmptyDir(platformsDirectoryPath).wait());
- var actualAppId = fs.readJson(tnsProjectFilePath).wait().id;
+ var actualAppId = fs.readJson(tnsProjectFilePath).wait()["nativescript"].id;
var expectedAppId = appId;
assert.equal(actualAppId, expectedAppId);
@@ -139,4 +141,135 @@ describe("Project Service Tests", () => {
projectIntegrationTest.assertProject(tempFolder, projectName, options.appid).wait();
});
});
-});
\ No newline at end of file
+});
+
+function createTestInjector() {
+ var testInjector = new yok.Yok();
+
+ testInjector.register("errors", stubs.ErrorsStub);
+ testInjector.register('logger', stubs.LoggerStub);
+ testInjector.register("projectService", ProjectServiceLib.ProjectService);
+ testInjector.register("projectHelper", ProjectHelperLib.ProjectHelper);
+ testInjector.register("projectTemplatesService", stubs.ProjectTemplatesService);
+ testInjector.register("projectNameValidator", mockProjectNameValidator);
+
+ testInjector.register("fs", fsLib.FileSystem);
+ testInjector.register("projectDataService", ProjectDataServiceLib.ProjectDataService);
+
+ testInjector.register("staticConfig", StaticConfigLib.StaticConfig);
+
+ testInjector.register("npm", NpmLib.NodePackageManager);
+ testInjector.register("httpClient", HttpClientLib.HttpClient);
+ testInjector.register("config", {});
+ testInjector.register("lockfile", stubs.LockFile);
+
+ testInjector.register('projectData', ProjectDataLib.ProjectData);
+
+ return testInjector;
+}
+
+describe("project upgrade procedure tests", () => {
+ it("should throw error when no nativescript project folder specified", () => {
+ var testInjector = createTestInjector();
+ var tempFolder = temp.mkdirSync("project upgrade");
+ options.path = tempFolder;
+ var isErrorThrown = false;
+
+ try {
+ testInjector.resolve("projectData"); // This should trigger upgrade procedure
+ } catch(err) {
+ isErrorThrown = true;
+ var expectedErrorMessage = "No project found at or above '%s' and neither was a --path specified.," + tempFolder;
+ assert.equal(expectedErrorMessage, err.toString());
+ }
+
+ assert.isTrue(isErrorThrown);
+ });
+ it("should upgrade project when .tnsproject file exists but package.json file doesn't exist", () => {
+ var testInjector = createTestInjector();
+ var fs: IFileSystem = testInjector.resolve("fs");
+
+ var tempFolder = temp.mkdirSync("projectUpgradeTest2");
+ options.path = tempFolder;
+ var tnsProjectData = {
+ "id": "org.nativescript.Test",
+ "tns-ios": {
+ "version": "1.0.0"
+ }
+ };
+ var tnsProjectFilePath = path.join(tempFolder, ".tnsproject");
+ fs.writeJson(tnsProjectFilePath, tnsProjectData).wait();
+
+ testInjector.resolve("projectData"); // This should trigger upgrade procedure
+
+ var packageJsonFilePath = path.join(tempFolder, "package.json");
+ var packageJsonFileContent = require(packageJsonFilePath);
+ assert.isTrue(fs.exists(packageJsonFilePath).wait());
+ assert.isFalse(fs.exists(tnsProjectFilePath).wait());
+ assert.deepEqual(tnsProjectData, packageJsonFileContent["nativescript"]);
+ });
+ it("should upgrade project when .tnsproject and package.json exist but nativescript key is not presented in package.json file", () => {
+ var testInjector = createTestInjector();
+ var fs: IFileSystem = testInjector.resolve("fs");
+
+ var tempFolder = temp.mkdirSync("projectUpgradeTest3");
+ options.path = tempFolder;
+ var tnsProjectData = {
+ "id": "org.nativescript.Test",
+ "tns-ios": {
+ "version": "1.0.1"
+ }
+ };
+ var packageJsonData = {
+ "name": "testModuleName",
+ "version": "0.0.0",
+ "dependencies": {
+ "myFirstDep": "0.0.1"
+ }
+ }
+ let tnsProjectFilePath = path.join(tempFolder, ".tnsproject");
+ fs.writeJson(tnsProjectFilePath, tnsProjectData).wait();
+
+ var packageJsonFilePath = path.join(tempFolder, "package.json");
+ fs.writeJson(packageJsonFilePath, packageJsonData).wait();
+
+ testInjector.resolve("projectData"); // This should trigger upgrade procedure
+
+ var packageJsonFileContent = require(packageJsonFilePath);
+ var expectedPackageJsonContent: any = packageJsonData;
+ expectedPackageJsonContent["nativescript"] = tnsProjectData;
+ assert.deepEqual(expectedPackageJsonContent, packageJsonFileContent);
+ });
+ it("shouldn't upgrade project when .tnsproject and package.json exist and nativescript key is presented in package.json file", () => {
+ var testInjector = createTestInjector();
+ var fs: IFileSystem = testInjector.resolve("fs");
+
+ var tempFolder = temp.mkdirSync("projectUpgradeTest4");
+ options.path = tempFolder;
+ var tnsProjectData = {
+
+ };
+ var packageJsonData = {
+ "name": "testModuleName",
+ "version": "0.0.0",
+ "dependencies": {
+ "myFirstDep": "0.0.2"
+ },
+ "nativescript": {
+ "id": "org.nativescript.Test",
+ "tns-ios": {
+ "version": "1.0.2"
+ }
+ }
+ }
+
+ fs.writeJson(path.join(tempFolder, ".tnsproject"), tnsProjectData).wait();
+ fs.writeJson(path.join(tempFolder, "package.json"), packageJsonData).wait();
+ testInjector.resolve("projectData"); // This should trigger upgrade procedure
+
+ var packageJsonFilePath = path.join(tempFolder, "package.json");
+ var packageJsonFileContent = require(packageJsonFilePath);
+
+ assert.deepEqual(packageJsonData, packageJsonFileContent);
+ });
+});
\ No newline at end of file