Skip to content

Commit 00e7a30

Browse files
authored
Merge pull request #3356 from NativeScript/kddimitrov/nsconfig-app-folder
Kddimitrov/nsconfig app folder
2 parents 61f4b6c + 2b5ef94 commit 00e7a30

28 files changed

+346
-97
lines changed

PublicAPI.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const tns = require("nativescript");
1111
* [projectService](#projectservice)
1212
* [createProject](#createproject)
1313
* [isValidNativeScriptProject](#isvalidnativescriptproject)
14+
* [projectDataService](#projectdataservice)
15+
* [getProjectData](#getprojectdata)
16+
* [getProjectDataFromContent](#getprojectdatafromcontent)
1417
* [extensibilityService](#extensibilityservice)
1518
* [installExtension](#installextension)
1619
* [uninstallExtension](#uninstallextension)
@@ -109,6 +112,81 @@ const isValidProject = tns.projectService.isValidNativeScriptProject("/tmp/myPro
109112
console.log(isValidProject); // true or false
110113
```
111114
115+
## projectDataService
116+
`projectDataService` provides a way to get information about a NativeScript project.
117+
118+
A common interface describing the results of a method is `IProjectData`:
119+
120+
```TypeScript
121+
interface IProjectData extends IProjectDir {
122+
projectName: string;
123+
platformsDir: string;
124+
projectFilePath: string;
125+
projectId?: string;
126+
dependencies: any;
127+
devDependencies: IStringDictionary;
128+
appDirectoryPath: string;
129+
appResourcesDirectoryPath: string;
130+
projectType: string;
131+
nsConfig: INsConfig;
132+
/**
133+
* Initializes project data with the given project directory. If none supplied defaults to cwd.
134+
* @param {string} projectDir Project root directory.
135+
* @returns {void}
136+
*/
137+
initializeProjectData(projectDir?: string): void;
138+
/**
139+
* Initializes project data with the given package.json, nsconfig.json content and project directory. If none supplied defaults to cwd.
140+
* @param {string} packageJsonContent: string
141+
* @param {string} nsconfigContent: string
142+
* @param {string} projectDir Project root directory.
143+
* @returns {void}
144+
*/
145+
initializeProjectDataFromContent(packageJsonContent: string, nsconfigContent: string, projectDir?: string): void;
146+
getAppDirectoryPath(projectDir?: string): string;
147+
getAppDirectoryRelativePath(): string;
148+
getAppResourcesDirectoryPath(projectDir?: string): string;
149+
getAppResourcesRelativeDirectoryPath(): string;
150+
}
151+
152+
interface IProjectDir {
153+
projectDir: string;
154+
}
155+
156+
interface INsConfig {
157+
appPath?: string;
158+
appResourcesPath?:string;
159+
}
160+
```
161+
162+
### getProjectData
163+
Returns an initialized IProjectData object containing data about the NativeScript project in the provided `projectDir`.
164+
165+
* Definition:
166+
```TypeScript
167+
/**
168+
* Returns an initialized IProjectData object containing data about the NativeScript project in the provided projectDir
169+
* @param {string} projectDir The path to the project
170+
* @returns {IProjectData} Information about the NativeScript project
171+
*/
172+
getProjectData(projectDir: string): IProjectData
173+
```
174+
175+
### getProjectDataFromContent
176+
Returns an IProjectData object that is initialized with the provided package.json content, nsconfig.json content and `projectDir`.
177+
178+
* Definition:
179+
```TypeScript
180+
/**
181+
* Returns an initialized IProjectData object containing data about the NativeScript project in the provided projectDir
182+
* @param {string} packageJsonContent The content of the project.json file in the root of the project
183+
* @param {string} nsconfigContent The content of the nsconfig.json file in the root of the project
184+
* @param {string} projectDir The path to the project
185+
* @returns {IProjectData} Information about the NativeScript project
186+
*/
187+
getProjectDataFromContent(packageJsonContent: string, nsconfigContent: string, projectDir?: string): IProjectData
188+
```
189+
112190
## extensibilityService
113191
`extensibilityService` module gives access to methods for working with CLI's extensions - list, install, uninstall, load them. The extensions add new functionality to CLI, so once an extension is loaded, all methods added to it's public API are accessible directly through CLI when it is used as a library. Extensions may also add new commands, so they are accessible through command line when using NativeScript CLI.
114192

lib/bootstrap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ $injector.require("options", "./options");
66
$injector.require("nativescript-cli", "./nativescript-cli");
77

88
$injector.require("projectData", "./project-data");
9-
$injector.require("projectDataService", "./services/project-data-service");
9+
$injector.requirePublic("projectDataService", "./services/project-data-service");
1010
$injector.requirePublic("projectService", "./services/project-service");
1111
$injector.require("androidProjectService", "./services/android-project-service");
1212
$injector.require("iOSEntitlementsService", "./services/ios-entitlements-service");

lib/commands/test-init.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class TestInitCommand implements ICommand {
6868

6969
await this.$pluginsService.add('nativescript-unit-test-runner', this.$projectData);
7070

71-
const testsDir = path.join(projectDir, 'app/tests');
71+
const testsDir = path.join(this.$projectData.appDirectoryPath, 'tests');
7272
let shouldCreateSampleTests = true;
7373
if (this.$fs.exists(testsDir)) {
7474
this.$logger.info('app/tests/ directory already exists, will not create an example test project.');

lib/common

lib/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export const BUILD_DIR = "build";
2828
export const OUTPUTS_DIR = "outputs";
2929
export const APK_DIR = "apk";
3030
export const RESOURCES_DIR = "res";
31+
export const CONFIG_NS_FILE_NAME = "nsconfig.json";
32+
export const CONFIG_NS_APP_RESOURCES_ENTRY = "appResourcesPath";
33+
export const CONFIG_NS_APP_ENTRY = "appPath";
3134

3235
export class PackageVersion {
3336
static NEXT = "next";

lib/definitions/livesync.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ interface IDebugLiveSyncService extends ILiveSyncService {
214214
* @param {ILiveSyncInfo} liveSyncData Information needed for livesync - for example if bundle is passed or if a release build should be performed.
215215
* @returns {Promise<string[]>} The glob patterns.
216216
*/
217-
getWatcherPatterns(liveSyncData: ILiveSyncInfo): Promise<string[]>;
217+
getWatcherPatterns(liveSyncData: ILiveSyncInfo, projectData: IProjectData): Promise<string[]>;
218218

219219
/**
220220
* Prints debug information.

lib/definitions/project.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ interface IProjectService {
5353
isValidNativeScriptProject(pathToProject?: string): boolean;
5454
}
5555

56+
interface INsConfig {
57+
appPath?: string;
58+
appResourcesPath?:string;
59+
}
60+
5661
interface IProjectData extends IProjectDir {
5762
projectName: string;
5863
platformsDir: string;
@@ -63,12 +68,18 @@ interface IProjectData extends IProjectDir {
6368
appDirectoryPath: string;
6469
appResourcesDirectoryPath: string;
6570
projectType: string;
71+
nsConfig: INsConfig;
6672
/**
6773
* Initializes project data with the given project directory. If none supplied defaults to --path option or cwd.
6874
* @param {string} projectDir Project root directory.
6975
* @returns {void}
7076
*/
7177
initializeProjectData(projectDir?: string): void;
78+
initializeProjectDataFromContent(packageJsonContent: string, nsconfigContent: string, projectDir?: string): void;
79+
getAppDirectoryPath(projectDir?: string): string;
80+
getAppDirectoryRelativePath(): string;
81+
getAppResourcesDirectoryPath(projectDir?: string): string;
82+
getAppResourcesRelativeDirectoryPath(): string;
7283
}
7384

7485
interface IProjectDataService {

lib/project-data.ts

Lines changed: 112 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as constants from "./constants";
22
import * as path from "path";
3+
import { parseJson } from "./common/helpers";
34
import { EOL } from "os";
45

56
interface IProjectType {
@@ -32,6 +33,7 @@ export class ProjectData implements IProjectData {
3233
public projectFilePath: string;
3334
public projectId: string;
3435
public projectName: string;
36+
public nsConfig: any;
3537
public appDirectoryPath: string;
3638
public appResourcesDirectoryPath: string;
3739
public dependencies: any;
@@ -47,46 +49,130 @@ export class ProjectData implements IProjectData {
4749

4850
public initializeProjectData(projectDir?: string): void {
4951
projectDir = projectDir || this.$projectHelper.projectDir;
52+
5053
// If no project found, projectDir should be null
5154
if (projectDir) {
52-
const projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
53-
let data: any = null;
55+
const projectFilePath = this.getProjectFilePath(projectDir);
5456

5557
if (this.$fs.exists(projectFilePath)) {
56-
let fileContent: any = null;
57-
try {
58-
fileContent = this.$fs.readJson(projectFilePath);
59-
data = fileContent[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE];
60-
} catch (err) {
61-
this.$errors.failWithoutHelp(`The project file ${this.projectFilePath} is corrupted. ${EOL}` +
62-
`Consider restoring an earlier version from your source control or backup.${EOL}` +
63-
`Additional technical info: ${err.toString()}`);
64-
}
65-
66-
if (data) {
67-
this.projectDir = projectDir;
68-
this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
69-
this.platformsDir = path.join(projectDir, constants.PLATFORMS_DIR_NAME);
70-
this.projectFilePath = projectFilePath;
71-
this.appDirectoryPath = path.join(projectDir, constants.APP_FOLDER_NAME);
72-
this.appResourcesDirectoryPath = path.join(projectDir, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME);
73-
this.projectId = data.id;
74-
this.dependencies = fileContent.dependencies;
75-
this.devDependencies = fileContent.devDependencies;
76-
this.projectType = this.getProjectType();
77-
78-
return;
79-
}
58+
const packageJsonContent = this.$fs.readText(projectFilePath);
59+
const nsConfigContent = this.getNsConfigContent(projectDir);
60+
61+
this.initializeProjectDataFromContent(packageJsonContent, nsConfigContent, projectDir);
8062
}
63+
64+
return;
65+
}
66+
67+
this.errorInvalidProject(projectDir);
68+
}
69+
70+
public initializeProjectDataFromContent(packageJsonContent: string, nsconfigContent: string, projectDir?: string): void {
71+
projectDir = projectDir || this.$projectHelper.projectDir || "";
72+
const projectFilePath = this.getProjectFilePath(projectDir);
73+
// If no project found, projectDir should be null
74+
let nsData = null;
75+
let nsConfig: INsConfig = null;
76+
let packageJsonData = null;
77+
78+
try {
79+
packageJsonData = parseJson(packageJsonContent);
80+
nsData = packageJsonData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE];
81+
} catch (err) {
82+
this.$errors.failWithoutHelp(`The project file ${this.projectFilePath} is corrupted. ${EOL}` +
83+
`Consider restoring an earlier version from your source control or backup.${EOL}` +
84+
`Additional technical info: ${err.toString()}`);
85+
}
86+
87+
try {
88+
nsConfig = nsconfigContent ? <INsConfig>parseJson(nsconfigContent) : null;
89+
} catch (err) {
90+
this.$errors.failWithoutHelp(`The NativeScript configuration file ${constants.CONFIG_NS_FILE_NAME} is corrupted. ${EOL}` +
91+
`Consider restoring an earlier version from your source control or backup.${EOL}` +
92+
`Additional technical info: ${err.toString()}`);
8193
}
8294

95+
if (nsData) {
96+
this.projectDir = projectDir;
97+
this.projectName = this.$projectHelper.sanitizeName(path.basename(projectDir));
98+
this.platformsDir = path.join(projectDir, constants.PLATFORMS_DIR_NAME);
99+
this.projectFilePath = projectFilePath;
100+
this.projectId = nsData.id;
101+
this.dependencies = packageJsonData.dependencies;
102+
this.devDependencies = packageJsonData.devDependencies;
103+
this.projectType = this.getProjectType();
104+
this.nsConfig = nsConfig;
105+
this.appDirectoryPath = this.getAppDirectoryPath();
106+
this.appResourcesDirectoryPath = this.getAppResourcesDirectoryPath();
107+
108+
return;
109+
}
110+
111+
this.errorInvalidProject(projectDir);
112+
}
113+
114+
private errorInvalidProject(projectDir: string): void {
83115
const currentDir = path.resolve(".");
84116
this.$logger.trace(`Unable to find project. projectDir: ${projectDir}, options.path: ${this.$options.path}, ${currentDir}`);
85117

86118
// This is the case when no project file found
87119
this.$errors.fail("No project found at or above '%s' and neither was a --path specified.", projectDir || this.$options.path || currentDir);
88120
}
89121

122+
private getProjectFilePath(projectDir: string): string {
123+
return path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
124+
}
125+
126+
public getAppResourcesDirectoryPath(projectDir?: string): string {
127+
const appResourcesRelativePath = this.getAppResourcesRelativeDirectoryPath();
128+
129+
return this.resolveToProjectDir(appResourcesRelativePath, projectDir);
130+
}
131+
132+
public getAppResourcesRelativeDirectoryPath(): string {
133+
if (this.nsConfig && this.nsConfig[constants.CONFIG_NS_APP_RESOURCES_ENTRY]) {
134+
return this.nsConfig[constants.CONFIG_NS_APP_RESOURCES_ENTRY];
135+
}
136+
137+
return path.join(this.getAppDirectoryRelativePath(), constants.APP_RESOURCES_FOLDER_NAME);
138+
}
139+
140+
public getAppDirectoryPath(projectDir?: string): string {
141+
const appRelativePath = this.getAppDirectoryRelativePath();
142+
143+
return this.resolveToProjectDir(appRelativePath, projectDir);
144+
}
145+
146+
public getAppDirectoryRelativePath(): string {
147+
if (this.nsConfig && this.nsConfig[constants.CONFIG_NS_APP_ENTRY]) {
148+
return this.nsConfig[constants.CONFIG_NS_APP_ENTRY];
149+
}
150+
151+
return constants.APP_FOLDER_NAME;
152+
}
153+
154+
private getNsConfigContent(projectDir: string): string {
155+
const configNSFilePath = path.join(projectDir, constants.CONFIG_NS_FILE_NAME);
156+
157+
if (!this.$fs.exists(configNSFilePath)) {
158+
return null;
159+
}
160+
161+
return this.$fs.readText(configNSFilePath);
162+
}
163+
164+
private resolveToProjectDir(pathToResolve: string, projectDir?: string): string {
165+
if (!projectDir) {
166+
projectDir = this.projectDir;
167+
}
168+
169+
if (!projectDir) {
170+
return null;
171+
}
172+
173+
return path.resolve(projectDir, pathToResolve);
174+
}
175+
90176
private getProjectType(): string {
91177
let detectedProjectType = _.find(ProjectData.PROJECT_TYPES, (projectType) => projectType.isDefaultProjectType).type;
92178

lib/providers/project-files-provider.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,33 @@ import { ProjectFilesProviderBase } from "../common/services/project-files-provi
66
export class ProjectFilesProvider extends ProjectFilesProviderBase {
77
constructor(private $platformsData: IPlatformsData,
88
$mobileHelper: Mobile.IMobileHelper,
9-
$options:IOptions) {
10-
super($mobileHelper, $options);
9+
$options: IOptions) {
10+
super($mobileHelper, $options);
1111
}
1212

13-
private static INTERNAL_NONPROJECT_FILES = [ "**/*.ts" ];
13+
private static INTERNAL_NONPROJECT_FILES = ["**/*.ts"];
1414

1515
public mapFilePath(filePath: string, platform: string, projectData: IProjectData, projectFilesConfig: IProjectFilesConfig): string {
1616
const platformData = this.$platformsData.getPlatformData(platform.toLowerCase(), projectData);
1717
const parsedFilePath = this.getPreparedFilePath(filePath, projectFilesConfig);
1818
let mappedFilePath = "";
19+
let relativePath;
1920
if (parsedFilePath.indexOf(constants.NODE_MODULES_FOLDER_NAME) > -1) {
20-
const relativePath = path.relative(path.join(projectData.projectDir, constants.NODE_MODULES_FOLDER_NAME), parsedFilePath);
21+
relativePath = path.relative(path.join(projectData.projectDir, constants.NODE_MODULES_FOLDER_NAME), parsedFilePath);
2122
mappedFilePath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, constants.TNS_MODULES_FOLDER_NAME, relativePath);
2223
} else {
23-
mappedFilePath = path.join(platformData.appDestinationDirectoryPath, path.relative(projectData.projectDir, parsedFilePath));
24+
relativePath = path.relative(projectData.appDirectoryPath, parsedFilePath);
25+
mappedFilePath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, relativePath);
2426
}
2527

26-
const appResourcesDirectoryPath = path.join(constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME);
28+
const appResourcesDirectoryPath = projectData.appResourcesDirectoryPath;
2729
const platformSpecificAppResourcesDirectoryPath = path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName);
2830
if (parsedFilePath.indexOf(appResourcesDirectoryPath) > -1 && parsedFilePath.indexOf(platformSpecificAppResourcesDirectoryPath) === -1) {
2931
return null;
3032
}
3133

3234
if (parsedFilePath.indexOf(platformSpecificAppResourcesDirectoryPath) > -1) {
33-
const appResourcesRelativePath = path.relative(path.join(projectData.projectDir, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME,
35+
const appResourcesRelativePath = path.relative(path.join(projectData.appResourcesDirectoryPath,
3436
platformData.normalizedPlatformName), parsedFilePath);
3537
mappedFilePath = path.join(platformData.platformProjectService.getAppResourcesDestinationDirectoryPath(projectData), appResourcesRelativePath);
3638
}

0 commit comments

Comments
 (0)