Skip to content

Commit 8cb5a4a

Browse files
FatmeFatme
Fatme
authored and
Fatme
committed
Merge pull request #476 from NativeScript/fatme/package.json
Remove .tnsproject and introduce package.json
2 parents 6bbae8a + c4ec922 commit 8cb5a4a

File tree

5 files changed

+219
-25
lines changed

5 files changed

+219
-25
lines changed

lib/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export class Configuration extends configBaseLib.ConfigBase implements IConfigur
2121
$injector.register("config", Configuration);
2222

2323
export class StaticConfig extends staticConfigBaseLibPath.StaticConfigBase implements IStaticConfig {
24-
public PROJECT_FILE_NAME = ".tnsproject";
24+
public PROJECT_FILE_NAME = "package.json";
25+
public CLIENT_NAME_KEY_IN_PROJECT_FILE = "nativescript";
2526
public CLIENT_NAME = "tns";
2627
public CLIENT_NAME_ALIAS = "NativeScript";
2728
public ANALYTICS_API_KEY = "5752dabccfc54c4ab82aea9626b7338e";

lib/project-data.ts

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
///<reference path=".d.ts"/>
22
"use strict";
33

4+
import constants = require("./constants");
45
import path = require("path");
56
import os = require("os");
7+
import options = require("./common/options");
68

79
export class ProjectData implements IProjectData {
10+
private static OLD_PROJECT_FILE_NAME = ".tnsproject";
11+
812
public projectDir: string;
913
public platformsDir: string;
1014
public projectFilePath: string;
@@ -13,37 +17,87 @@ export class ProjectData implements IProjectData {
1317

1418
constructor(private $fs: IFileSystem,
1519
private $errors: IErrors,
20+
private $logger: ILogger,
1621
private $projectHelper: IProjectHelper,
1722
private $staticConfig: IStaticConfig) {
1823
this.initializeProjectData().wait();
1924
}
2025

2126
private initializeProjectData(): IFuture<void> {
2227
return(() => {
23-
var projectDir = this.$projectHelper.projectDir;
28+
let projectDir = this.$projectHelper.projectDir;
2429
// If no project found, projectDir should be null
2530
if(projectDir) {
26-
this.projectDir = projectDir;
27-
this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
28-
this.platformsDir = path.join(projectDir, "platforms");
29-
this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
31+
this.initializeProjectDataCore(projectDir);
32+
let data: any = null;
3033

3134
if (this.$fs.exists(this.projectFilePath).wait()) {
3235
try {
33-
var fileContent = this.$fs.readJson(this.projectFilePath).wait();
34-
this.projectId = fileContent.id;
36+
let fileContent = this.$fs.readJson(this.projectFilePath).wait();
37+
data = fileContent[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE];
3538
} catch (err) {
3639
this.$errors.fail({formatStr: "The project file %s is corrupted." + os.EOL +
3740
"Consider restoring an earlier version from your source control or backup." + os.EOL +
3841
"Additional technical info: %s",
3942
suppressCommandHelp: true},
4043
this.projectFilePath, err.toString());
4144
}
42-
}
45+
46+
if(data) {
47+
this.projectId = data.id;
48+
} else { // This is the case when we have package.json file but nativescipt key is not presented in it
49+
this.tryToUpgradeProject().wait();
50+
}
51+
}
52+
} else { // This is the case when no project file found
53+
this.tryToUpgradeProject().wait();
54+
}
55+
}).future<void>()();
56+
}
57+
58+
private throwNoProjectFoundError(): void {
59+
this.$errors.fail("No project found at or above '%s' and neither was a --path specified.", options.path || path.resolve("."));
60+
}
61+
62+
private tryToUpgradeProject(): IFuture<void> {
63+
return (() => {
64+
let projectDir = this.projectDir || path.resolve(options.path || ".");
65+
let oldProjectFilePath = path.join(projectDir, ProjectData.OLD_PROJECT_FILE_NAME);
66+
if(this.$fs.exists(oldProjectFilePath).wait()) {
67+
this.upgrade(projectDir, oldProjectFilePath).wait();
4368
} else {
44-
this.$errors.fail("No project found at or above '%s' and neither was a --path specified.", process.cwd());
69+
this.throwNoProjectFoundError();
4570
}
4671
}).future<void>()();
4772
}
73+
74+
private upgrade(projectDir: string, oldProjectFilePath: string): IFuture<void> {
75+
return (() => {
76+
try {
77+
let oldProjectData = this.$fs.readJson(oldProjectFilePath).wait();
78+
79+
let newProjectFilePath = this.projectFilePath || path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
80+
let newProjectData = this.$fs.exists(newProjectFilePath).wait() ? this.$fs.readJson(newProjectFilePath).wait() : {};
81+
newProjectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = oldProjectData;
82+
this.$fs.writeJson(newProjectFilePath, newProjectData).wait();
83+
84+
this.$fs.deleteFile(oldProjectFilePath).wait();
85+
} catch(err) {
86+
this.$logger.out("An error occurred while upgrading your project.");
87+
throw err;
88+
}
89+
90+
this.initializeProjectDataCore(projectDir);
91+
92+
this.$logger.out("Successfully upgraded your project file.");
93+
}).future<void>()();
94+
}
95+
96+
private initializeProjectDataCore(projectDir: string): void {
97+
this.projectDir = projectDir;
98+
this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
99+
this.platformsDir = path.join(projectDir, "platforms");
100+
this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
101+
}
48102
}
49103
$injector.register("projectData", ProjectData);

lib/services/project-data-service.ts

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,54 @@
11
///<reference path="../.d.ts"/>
22
"use strict";
33

4+
import constants = require("./../constants");
45
import path = require("path");
56
import assert = require("assert");
67

78
export class ProjectDataService implements IProjectDataService {
8-
private projectFileName: string;
9+
private projectFilePath: string;
910
private projectData: IDictionary<any>;
1011

1112
constructor(private $fs: IFileSystem,
12-
private $staticConfig: IStaticConfig) {
13+
private $staticConfig: IStaticConfig,
14+
private $errors: IErrors,
15+
private $logger: ILogger) {
1316
}
1417

1518
public initialize(projectDir: string): void {
16-
if(!this.projectFileName) {
17-
this.projectFileName = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
19+
if(!this.projectFilePath) {
20+
this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
1821
}
1922
}
2023

2124
public getValue(propertyName: string): IFuture<any> {
2225
return (() => {
2326
this.loadProjectFile().wait();
24-
return this.projectData ? this.projectData[propertyName] : null;
27+
return this.projectData ? this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][propertyName] : null;
2528
}).future<string>()();
2629
}
2730

2831
public setValue(key: string, value: any): IFuture<void> {
2932
return (() => {
3033
this.loadProjectFile().wait();
31-
this.projectData[key] = value;
32-
this.$fs.writeJson(this.projectFileName, this.projectData, "\t").wait();
34+
if(!this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]) {
35+
this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = Object.create(null);
36+
}
37+
this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][key] = value;
38+
this.$fs.writeJson(this.projectFilePath, this.projectData, "\t").wait();
3339
}).future<void>()();
3440
}
3541

3642
private loadProjectFile(): IFuture<void> {
3743
return (() => {
38-
assert.ok(this.projectFileName, "Initialize method of projectDataService is not called");
44+
assert.ok(this.projectFilePath, "Initialize method of projectDataService is not called");
3945

4046
if(!this.projectData) {
41-
if(!this.$fs.exists(this.projectFileName).wait()) {
42-
this.$fs.writeFile(this.projectFileName, null).wait();
47+
if(!this.$fs.exists(this.projectFilePath).wait()) {
48+
this.$fs.writeFile(this.projectFilePath, null).wait();
4349
}
4450

45-
this.projectData = this.$fs.readJson(this.projectFileName).wait() || Object.create(null);
51+
this.projectData = this.$fs.readJson(this.projectFilePath).wait() || Object.create(null);
4652
}
4753
}).future<void>()();
4854
}

test/project-service.ts

Lines changed: 136 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import stubs = require('./stubs');
66

77
import ProjectServiceLib = require("../lib/services/project-service");
88
import ProjectDataServiceLib = require("../lib/services/project-data-service");
9+
import ProjectDataLib = require("../lib/project-data");
910
import ProjectHelperLib = require("../lib/common/project-helper");
1011
import StaticConfigLib = require("../lib/config");
1112
import NpmLib = require("../lib/node-package-manager");
1213
import HttpClientLib = require("../lib/common/http-client");
1314
import fsLib = require("../lib/common/file-system");
15+
import platformServiceLib = require("../lib/services/platform-service");
1416

1517
import path = require("path");
1618
import temp = require("temp");
@@ -64,7 +66,7 @@ class ProjectIntegrationTest {
6466
var projectDir = path.join(tempFolder, projectName);
6567
var appDirectoryPath = path.join(projectDir, "app");
6668
var platformsDirectoryPath = path.join(projectDir, "platforms");
67-
var tnsProjectFilePath = path.join(projectDir, ".tnsproject");
69+
let tnsProjectFilePath = path.join(projectDir, "package.json");
6870

6971
assert.isTrue(fs.exists(appDirectoryPath).wait());
7072
assert.isTrue(fs.exists(platformsDirectoryPath).wait());
@@ -73,7 +75,7 @@ class ProjectIntegrationTest {
7375
assert.isFalse(fs.isEmptyDir(appDirectoryPath).wait());
7476
assert.isTrue(fs.isEmptyDir(platformsDirectoryPath).wait());
7577

76-
var actualAppId = fs.readJson(tnsProjectFilePath).wait().id;
78+
var actualAppId = fs.readJson(tnsProjectFilePath).wait()["nativescript"].id;
7779
var expectedAppId = appId;
7880
assert.equal(actualAppId, expectedAppId);
7981

@@ -139,4 +141,135 @@ describe("Project Service Tests", () => {
139141
projectIntegrationTest.assertProject(tempFolder, projectName, options.appid).wait();
140142
});
141143
});
142-
});
144+
});
145+
146+
function createTestInjector() {
147+
var testInjector = new yok.Yok();
148+
149+
testInjector.register("errors", stubs.ErrorsStub);
150+
testInjector.register('logger', stubs.LoggerStub);
151+
testInjector.register("projectService", ProjectServiceLib.ProjectService);
152+
testInjector.register("projectHelper", ProjectHelperLib.ProjectHelper);
153+
testInjector.register("projectTemplatesService", stubs.ProjectTemplatesService);
154+
testInjector.register("projectNameValidator", mockProjectNameValidator);
155+
156+
testInjector.register("fs", fsLib.FileSystem);
157+
testInjector.register("projectDataService", ProjectDataServiceLib.ProjectDataService);
158+
159+
testInjector.register("staticConfig", StaticConfigLib.StaticConfig);
160+
161+
testInjector.register("npm", NpmLib.NodePackageManager);
162+
testInjector.register("httpClient", HttpClientLib.HttpClient);
163+
testInjector.register("config", {});
164+
testInjector.register("lockfile", stubs.LockFile);
165+
166+
testInjector.register('projectData', ProjectDataLib.ProjectData);
167+
168+
return testInjector;
169+
}
170+
171+
describe("project upgrade procedure tests", () => {
172+
it("should throw error when no nativescript project folder specified", () => {
173+
var testInjector = createTestInjector();
174+
var tempFolder = temp.mkdirSync("project upgrade");
175+
options.path = tempFolder;
176+
var isErrorThrown = false;
177+
178+
try {
179+
testInjector.resolve("projectData"); // This should trigger upgrade procedure
180+
} catch(err) {
181+
isErrorThrown = true;
182+
var expectedErrorMessage = "No project found at or above '%s' and neither was a --path specified.," + tempFolder;
183+
assert.equal(expectedErrorMessage, err.toString());
184+
}
185+
186+
assert.isTrue(isErrorThrown);
187+
});
188+
it("should upgrade project when .tnsproject file exists but package.json file doesn't exist", () => {
189+
var testInjector = createTestInjector();
190+
var fs: IFileSystem = testInjector.resolve("fs");
191+
192+
var tempFolder = temp.mkdirSync("projectUpgradeTest2");
193+
options.path = tempFolder;
194+
var tnsProjectData = {
195+
"id": "org.nativescript.Test",
196+
"tns-ios": {
197+
"version": "1.0.0"
198+
}
199+
};
200+
var tnsProjectFilePath = path.join(tempFolder, ".tnsproject");
201+
fs.writeJson(tnsProjectFilePath, tnsProjectData).wait();
202+
203+
testInjector.resolve("projectData"); // This should trigger upgrade procedure
204+
205+
var packageJsonFilePath = path.join(tempFolder, "package.json");
206+
var packageJsonFileContent = require(packageJsonFilePath);
207+
assert.isTrue(fs.exists(packageJsonFilePath).wait());
208+
assert.isFalse(fs.exists(tnsProjectFilePath).wait());
209+
assert.deepEqual(tnsProjectData, packageJsonFileContent["nativescript"]);
210+
});
211+
it("should upgrade project when .tnsproject and package.json exist but nativescript key is not presented in package.json file", () => {
212+
var testInjector = createTestInjector();
213+
var fs: IFileSystem = testInjector.resolve("fs");
214+
215+
var tempFolder = temp.mkdirSync("projectUpgradeTest3");
216+
options.path = tempFolder;
217+
var tnsProjectData = {
218+
"id": "org.nativescript.Test",
219+
"tns-ios": {
220+
"version": "1.0.1"
221+
}
222+
};
223+
var packageJsonData = {
224+
"name": "testModuleName",
225+
"version": "0.0.0",
226+
"dependencies": {
227+
"myFirstDep": "0.0.1"
228+
}
229+
}
230+
let tnsProjectFilePath = path.join(tempFolder, ".tnsproject");
231+
fs.writeJson(tnsProjectFilePath, tnsProjectData).wait();
232+
233+
var packageJsonFilePath = path.join(tempFolder, "package.json");
234+
fs.writeJson(packageJsonFilePath, packageJsonData).wait();
235+
236+
testInjector.resolve("projectData"); // This should trigger upgrade procedure
237+
238+
var packageJsonFileContent = require(packageJsonFilePath);
239+
var expectedPackageJsonContent: any = packageJsonData;
240+
expectedPackageJsonContent["nativescript"] = tnsProjectData;
241+
assert.deepEqual(expectedPackageJsonContent, packageJsonFileContent);
242+
});
243+
it("shouldn't upgrade project when .tnsproject and package.json exist and nativescript key is presented in package.json file", () => {
244+
var testInjector = createTestInjector();
245+
var fs: IFileSystem = testInjector.resolve("fs");
246+
247+
var tempFolder = temp.mkdirSync("projectUpgradeTest4");
248+
options.path = tempFolder;
249+
var tnsProjectData = {
250+
251+
};
252+
var packageJsonData = {
253+
"name": "testModuleName",
254+
"version": "0.0.0",
255+
"dependencies": {
256+
"myFirstDep": "0.0.2"
257+
},
258+
"nativescript": {
259+
"id": "org.nativescript.Test",
260+
"tns-ios": {
261+
"version": "1.0.2"
262+
}
263+
}
264+
}
265+
266+
fs.writeJson(path.join(tempFolder, ".tnsproject"), tnsProjectData).wait();
267+
fs.writeJson(path.join(tempFolder, "package.json"), packageJsonData).wait();
268+
testInjector.resolve("projectData"); // This should trigger upgrade procedure
269+
270+
var packageJsonFilePath = path.join(tempFolder, "package.json");
271+
var packageJsonFileContent = require(packageJsonFilePath);
272+
273+
assert.deepEqual(packageJsonData, packageJsonFileContent);
274+
});
275+
});

0 commit comments

Comments
 (0)