Skip to content

Commit 5d3f3a4

Browse files
authored
feat(react): official quick create for --react app (#5336)
1 parent 6583943 commit 5d3f3a4

File tree

9 files changed

+64
-10
lines changed

9 files changed

+64
-10
lines changed

docs/man_pages/project/creation/create.md

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Template | Command
5151
`Angular - Hello World`, `--ng`, `--angular` | tns create --template tns-template-hello-world-ng
5252
`Angular - SideDrawer` | tns create --template tns-template-drawer-navigation-ng
5353
`Angular - Tabs` | tns create --template tns-template-tab-navigation-ng
54+
`React - Hello World`, `--react`, `--reactjs` | tns create --template tns-template-blank-react
5455
`Vue.js - Blank`, `--vue`, `--vuejs` | tns create --template tns-template-blank-vue
5556
`Vue.js - SideDrawer`, | tns create --template tns-template-drawer-navigation-vue
5657
`Vue.js - Tabs` | tns create --template tns-template-tab-navigation-vue

lib/commands/create-project.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export class CreateProjectCommand implements ICommand {
4444
selectedTemplate = constants.ANGULAR_NAME;
4545
} else if (this.$options.vue) {
4646
selectedTemplate = constants.VUE_NAME;
47+
} else if (this.$options.react) {
48+
selectedTemplate = constants.REACT_NAME;
4749
} else {
4850
selectedTemplate = this.$options.template;
4951
}
@@ -82,6 +84,7 @@ export class CreateProjectCommand implements ICommand {
8284
private async interactiveFlavorSelection(adverb: string) {
8385
const flavorSelection = await this.$prompter.promptForDetailedChoice(`${adverb}, which style of NativeScript project would you like to use:`, [
8486
{ key: constants.NgFlavorName, description: "Learn more at https://nativescript.org/angular" },
87+
{ key: constants.ReactFlavorName, description: "Learn more at https://github.com/shirakaba/react-nativescript" },
8588
{ key: constants.VueFlavorName, description: "Learn more at https://nativescript.org/vue" },
8689
{ key: constants.TsFlavorName, description: "Learn more at https://nativescript.org/typescript" },
8790
{ key: constants.JsFlavorName, description: "Use NativeScript without any framework" },
@@ -96,8 +99,7 @@ export class CreateProjectCommand implements ICommand {
9699
this.$logger.printMarkdown(`# Let’s create a NativeScript app!`);
97100
this.$logger.printMarkdown(`
98101
Answer the following questions to help us build the right app for you. (Note: you
99-
can skip this prompt next time using the --template option, or the --ng, --vue, --ts,
100-
or --js flags.)
102+
can skip this prompt next time using the --template option, or the --ng, --react, --vue, --ts, or --js flags.)
101103
`);
102104
}
103105
}
@@ -114,6 +116,10 @@ or --js flags.)
114116
selectedFlavorTemplates.push(...this.getNgTemplates());
115117
break;
116118
}
119+
case constants.ReactFlavorName: {
120+
selectedFlavorTemplates.push(...this.getReactTemplates());
121+
break;
122+
}
117123
case constants.VueFlavorName: {
118124
selectedFlavorTemplates.push(...this.getVueTemplates());
119125
break;
@@ -200,6 +206,16 @@ or --js flags.)
200206
return templates;
201207
}
202208

209+
private getReactTemplates() {
210+
const templates = [{
211+
key: CreateProjectCommand.HelloWorldTemplateKey,
212+
value: constants.RESERVED_TEMPLATE_NAMES.react,
213+
description: CreateProjectCommand.HelloWorldTemplateDescription
214+
}];
215+
216+
return templates;
217+
}
218+
203219
private getVueTemplates() {
204220
const templates = [{
205221
key: CreateProjectCommand.BlankTemplateKey,

lib/common/commands/preuninstall.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { doesCurrentNpmCommandMatch, isInteractive } from "../helpers";
33
import { TrackActionNames, AnalyticsEventLabelDelimiter } from "../../constants";
44

55
export class PreUninstallCommand implements ICommand {
6-
// disabled for now (6/24/2020)
6+
// disabled for now (6/24/2020)
77
// private static FEEDBACK_FORM_URL = "https://www.nativescript.org/uninstall-feedback";
88

99
public allowedParameters: ICommandParameter[] = [];
@@ -38,11 +38,11 @@ export class PreUninstallCommand implements ICommand {
3838
}
3939

4040
private async handleFeedbackForm(): Promise<void> {
41-
// disabled for now (6/24/2020)
41+
// disabled for now (6/24/2020)
4242
// if (isInteractive()) {
4343
// this.$opener.open(PreUninstallCommand.FEEDBACK_FORM_URL);
44-
// }
45-
return Promise.resolve();
44+
// }
45+
return Promise.resolve();
4646
}
4747
}
4848

lib/common/test/unit-tests/preuninstall.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ describe("preuninstall", () => {
135135
assert.isTrue(isClearInspectorCacheCalled, "When uninstall is called, `clearInspectorCache` method must be called");
136136
});
137137

138-
// disabled (6/24/2020)
138+
// disabled (6/24/2020)
139139
// it("opens the uninstall feedback form when terminal is interactive and uninstall is called", async () => {
140140
// helpers.doesCurrentNpmCommandMatch = () => true;
141141
// helpers.isInteractive = () => true;

lib/constants.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ export const RESERVED_TEMPLATE_NAMES: IStringDictionary = {
110110
"vue": "tns-template-blank-vue",
111111
"typescript": "tns-template-hello-world-ts",
112112
"ng": "tns-template-hello-world-ng",
113-
"angular": "tns-template-hello-world-ng"
113+
"angular": "tns-template-hello-world-ng",
114+
"react": "tns-template-blank-react",
115+
"reactjs": "tns-template-blank-react"
114116
};
115117

116118
export const ANALYTICS_LOCAL_TEMPLATE_PREFIX = "localTemplate_";
@@ -138,8 +140,10 @@ export const VUE_NAME = "vue";
138140
export const ANGULAR_NAME = "angular";
139141
export const JAVASCRIPT_NAME = "javascript";
140142
export const TYPESCRIPT_NAME = "typescript";
143+
export const REACT_NAME = "react";
141144
export const NgFlavorName = "Angular";
142145
export const VueFlavorName = "Vue.js";
146+
export const ReactFlavorName = "React";
143147
export const TsFlavorName = "Plain TypeScript";
144148
export const JsFlavorName = "Plain JavaScript";
145149
export class ProjectTypes {

lib/declarations.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ interface IOptions extends IRelease, IDeviceIdentifier, IJustLaunch, IAvd, IAvai
567567
typescript: boolean;
568568
ng: boolean;
569569
angular: boolean;
570+
react: boolean;
570571
vue: boolean;
571572
vuejs: boolean;
572573
js: boolean;

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
},
1111
"main": "./lib/nativescript-cli-lib.js",
1212
"scripts": {
13-
"grunt": "grunt",
13+
"build": "grunt",
14+
"build.all": "grunt test",
1415
"setup": "npm i --ignore-scripts && ./node_modules/.bin/grunt",
1516
"test": "istanbul cover ./node_modules/mocha/bin/_mocha",
1617
"postinstall": "node postinstall.js",

test/project-commands.ts

+31
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ let validateProjectCallsCount: number;
1414
const dummyArgs = ["dummyArgsString"];
1515
const expectedFlavorChoices = [
1616
{ key: "Angular", description: "Learn more at https://nativescript.org/angular" },
17+
{ key: "React", description: "Learn more at https://github.com/shirakaba/react-nativescript" },
1718
{ key: "Vue.js", description: "Learn more at https://nativescript.org/vue" },
1819
{ key: "Plain TypeScript", description: "Learn more at https://nativescript.org/typescript" },
1920
{ key: "Plain JavaScript", description: "Use NativeScript without any framework" }
@@ -126,6 +127,16 @@ describe("Project commands tests", () => {
126127
assert.isTrue(createProjectCalledWithForce);
127128
});
128129

130+
it("should not fail when using only --react.", async () => {
131+
options.react = true;
132+
133+
await createProjectCommand.execute(dummyArgs);
134+
135+
assert.isTrue(isProjectCreated);
136+
assert.equal(validateProjectCallsCount, 1);
137+
assert.isTrue(createProjectCalledWithForce);
138+
});
139+
129140
it("should not fail when using only --tsc.", async () => {
130141
options.tsc = true;
131142

@@ -156,6 +167,16 @@ describe("Project commands tests", () => {
156167
assert.isTrue(createProjectCalledWithForce);
157168
});
158169

170+
it("should set the template name correctly when used --react.", async () => {
171+
options.react = true;
172+
173+
await createProjectCommand.execute(dummyArgs);
174+
175+
assert.deepEqual(selectedTemplateName, constants.REACT_NAME);
176+
assert.equal(validateProjectCallsCount, 1);
177+
assert.isTrue(createProjectCalledWithForce);
178+
});
179+
159180
it("should set the template name correctly when used --tsc.", async () => {
160181
options.tsc = true;
161182

@@ -219,5 +240,15 @@ describe("Project commands tests", () => {
219240
assert.equal(validateProjectCallsCount, 1);
220241
assert.isTrue(createProjectCalledWithForce);
221242
});
243+
244+
it("should ask for a template when react flavor is selected.", async () => {
245+
setupAnswers({ flavorAnswer: constants.ReactFlavorName, templateAnswer: "Hello World" });
246+
247+
await createProjectCommand.execute(dummyArgs);
248+
249+
assert.deepEqual(selectedTemplateName, "tns-template-blank-react");
250+
assert.equal(validateProjectCallsCount, 1);
251+
assert.isTrue(createProjectCalledWithForce);
252+
});
222253
});
223254
});

test/project-data.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe("projectData", () => {
105105
assertProjectType({ "react-nativescript": "*" }, null, "React");
106106
});
107107

108-
it("detects project as Svelte when react-nativescript exists as dependency and typescript is devDependency", () => {
108+
it("detects project as Svelte when svelte-native exists as dependency and typescript is devDependency", () => {
109109
assertProjectType({ "svelte-native": "*" }, null, "Svelte");
110110
});
111111

0 commit comments

Comments
 (0)