From 155f68d52e98eddf6d250239f353e6deea6a9875 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Fri, 26 Jun 2020 21:12:08 -0700 Subject: [PATCH 1/2] feat(react): official quick create for --react app --- docs/man_pages/project/creation/create.md | 1 + lib/commands/create-project.ts | 20 +++++++++++++-- lib/constants.ts | 6 ++++- lib/declarations.d.ts | 1 + package.json | 3 ++- test/project-commands.ts | 31 +++++++++++++++++++++++ test/project-data.ts | 2 +- 7 files changed, 59 insertions(+), 5 deletions(-) diff --git a/docs/man_pages/project/creation/create.md b/docs/man_pages/project/creation/create.md index 9ff5957602..9539408af5 100644 --- a/docs/man_pages/project/creation/create.md +++ b/docs/man_pages/project/creation/create.md @@ -51,6 +51,7 @@ Template | Command `Angular - Hello World`, `--ng`, `--angular` | tns create --template tns-template-hello-world-ng `Angular - SideDrawer` | tns create --template tns-template-drawer-navigation-ng `Angular - Tabs` | tns create --template tns-template-tab-navigation-ng +`React - Hello World`, `--react`, `--reactjs` | tns create --template tns-template-blank-react `Vue.js - Blank`, `--vue`, `--vuejs` | tns create --template tns-template-blank-vue `Vue.js - SideDrawer`, | tns create --template tns-template-drawer-navigation-vue `Vue.js - Tabs` | tns create --template tns-template-tab-navigation-vue diff --git a/lib/commands/create-project.ts b/lib/commands/create-project.ts index e1b9330e55..c22cc2e20b 100644 --- a/lib/commands/create-project.ts +++ b/lib/commands/create-project.ts @@ -44,6 +44,8 @@ export class CreateProjectCommand implements ICommand { selectedTemplate = constants.ANGULAR_NAME; } else if (this.$options.vue) { selectedTemplate = constants.VUE_NAME; + } else if (this.$options.react) { + selectedTemplate = constants.REACT_NAME; } else { selectedTemplate = this.$options.template; } @@ -82,6 +84,7 @@ export class CreateProjectCommand implements ICommand { private async interactiveFlavorSelection(adverb: string) { const flavorSelection = await this.$prompter.promptForDetailedChoice(`${adverb}, which style of NativeScript project would you like to use:`, [ { key: constants.NgFlavorName, description: "Learn more at https://nativescript.org/angular" }, + { key: constants.ReactFlavorName, description: "Learn more at https://github.com/shirakaba/react-nativescript" }, { key: constants.VueFlavorName, description: "Learn more at https://nativescript.org/vue" }, { key: constants.TsFlavorName, description: "Learn more at https://nativescript.org/typescript" }, { key: constants.JsFlavorName, description: "Use NativeScript without any framework" }, @@ -96,8 +99,7 @@ export class CreateProjectCommand implements ICommand { this.$logger.printMarkdown(`# Let’s create a NativeScript app!`); this.$logger.printMarkdown(` Answer the following questions to help us build the right app for you. (Note: you -can skip this prompt next time using the --template option, or the --ng, --vue, --ts, -or --js flags.) +can skip this prompt next time using the --template option, or the --ng, --react, --vue, --ts, or --js flags.) `); } } @@ -114,6 +116,10 @@ or --js flags.) selectedFlavorTemplates.push(...this.getNgTemplates()); break; } + case constants.ReactFlavorName: { + selectedFlavorTemplates.push(...this.getReactTemplates()); + break; + } case constants.VueFlavorName: { selectedFlavorTemplates.push(...this.getVueTemplates()); break; @@ -200,6 +206,16 @@ or --js flags.) return templates; } + private getReactTemplates() { + const templates = [{ + key: CreateProjectCommand.HelloWorldTemplateKey, + value: constants.RESERVED_TEMPLATE_NAMES.react, + description: CreateProjectCommand.HelloWorldTemplateDescription + }]; + + return templates; + } + private getVueTemplates() { const templates = [{ key: CreateProjectCommand.BlankTemplateKey, diff --git a/lib/constants.ts b/lib/constants.ts index ce26706ff5..81fb505544 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -110,7 +110,9 @@ export const RESERVED_TEMPLATE_NAMES: IStringDictionary = { "vue": "tns-template-blank-vue", "typescript": "tns-template-hello-world-ts", "ng": "tns-template-hello-world-ng", - "angular": "tns-template-hello-world-ng" + "angular": "tns-template-hello-world-ng", + "react": "tns-template-blank-react", + "reactjs": "tns-template-blank-react" }; export const ANALYTICS_LOCAL_TEMPLATE_PREFIX = "localTemplate_"; @@ -138,8 +140,10 @@ export const VUE_NAME = "vue"; export const ANGULAR_NAME = "angular"; export const JAVASCRIPT_NAME = "javascript"; export const TYPESCRIPT_NAME = "typescript"; +export const REACT_NAME = "react"; export const NgFlavorName = "Angular"; export const VueFlavorName = "Vue.js"; +export const ReactFlavorName = "React"; export const TsFlavorName = "Plain TypeScript"; export const JsFlavorName = "Plain JavaScript"; export class ProjectTypes { diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 47b945d5e4..3f70c8cb1f 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -567,6 +567,7 @@ interface IOptions extends IRelease, IDeviceIdentifier, IJustLaunch, IAvd, IAvai typescript: boolean; ng: boolean; angular: boolean; + react: boolean; vue: boolean; vuejs: boolean; js: boolean; diff --git a/package.json b/package.json index 0d9707934b..f0ce195ab5 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ }, "main": "./lib/nativescript-cli-lib.js", "scripts": { - "grunt": "grunt", + "build": "grunt", + "build.all": "grunt test", "setup": "npm i --ignore-scripts && ./node_modules/.bin/grunt", "test": "istanbul cover ./node_modules/mocha/bin/_mocha", "postinstall": "node postinstall.js", diff --git a/test/project-commands.ts b/test/project-commands.ts index 99af2cb4eb..f814104776 100644 --- a/test/project-commands.ts +++ b/test/project-commands.ts @@ -14,6 +14,7 @@ let validateProjectCallsCount: number; const dummyArgs = ["dummyArgsString"]; const expectedFlavorChoices = [ { key: "Angular", description: "Learn more at https://nativescript.org/angular" }, + { key: "React", description: "Learn more at https://github.com/shirakaba/react-nativescript" }, { key: "Vue.js", description: "Learn more at https://nativescript.org/vue" }, { key: "Plain TypeScript", description: "Learn more at https://nativescript.org/typescript" }, { key: "Plain JavaScript", description: "Use NativeScript without any framework" } @@ -126,6 +127,16 @@ describe("Project commands tests", () => { assert.isTrue(createProjectCalledWithForce); }); + it("should not fail when using only --react.", async () => { + options.react = true; + + await createProjectCommand.execute(dummyArgs); + + assert.isTrue(isProjectCreated); + assert.equal(validateProjectCallsCount, 1); + assert.isTrue(createProjectCalledWithForce); + }); + it("should not fail when using only --tsc.", async () => { options.tsc = true; @@ -156,6 +167,16 @@ describe("Project commands tests", () => { assert.isTrue(createProjectCalledWithForce); }); + it("should set the template name correctly when used --react.", async () => { + options.react = true; + + await createProjectCommand.execute(dummyArgs); + + assert.deepEqual(selectedTemplateName, constants.REACT_NAME); + assert.equal(validateProjectCallsCount, 1); + assert.isTrue(createProjectCalledWithForce); + }); + it("should set the template name correctly when used --tsc.", async () => { options.tsc = true; @@ -219,5 +240,15 @@ describe("Project commands tests", () => { assert.equal(validateProjectCallsCount, 1); assert.isTrue(createProjectCalledWithForce); }); + + it("should ask for a template when react flavor is selected.", async () => { + setupAnswers({ flavorAnswer: constants.ReactFlavorName, templateAnswer: "Hello World" }); + + await createProjectCommand.execute(dummyArgs); + + assert.deepEqual(selectedTemplateName, "tns-template-blank-react"); + assert.equal(validateProjectCallsCount, 1); + assert.isTrue(createProjectCalledWithForce); + }); }); }); diff --git a/test/project-data.ts b/test/project-data.ts index 3cf98eceb2..c99d22e252 100644 --- a/test/project-data.ts +++ b/test/project-data.ts @@ -105,7 +105,7 @@ describe("projectData", () => { assertProjectType({ "react-nativescript": "*" }, null, "React"); }); - it("detects project as Svelte when react-nativescript exists as dependency and typescript is devDependency", () => { + it("detects project as Svelte when svelte-native exists as dependency and typescript is devDependency", () => { assertProjectType({ "svelte-native": "*" }, null, "Svelte"); }); From a595041d57736b4e922cc5bbf48064db5396f0e3 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Fri, 26 Jun 2020 23:16:47 -0700 Subject: [PATCH 2/2] chore: cleanup --- lib/common/commands/preuninstall.ts | 8 ++++---- lib/common/test/unit-tests/preuninstall.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/common/commands/preuninstall.ts b/lib/common/commands/preuninstall.ts index 780cf29438..58d3486e0e 100644 --- a/lib/common/commands/preuninstall.ts +++ b/lib/common/commands/preuninstall.ts @@ -3,7 +3,7 @@ import { doesCurrentNpmCommandMatch, isInteractive } from "../helpers"; import { TrackActionNames, AnalyticsEventLabelDelimiter } from "../../constants"; export class PreUninstallCommand implements ICommand { - // disabled for now (6/24/2020) + // disabled for now (6/24/2020) // private static FEEDBACK_FORM_URL = "https://www.nativescript.org/uninstall-feedback"; public allowedParameters: ICommandParameter[] = []; @@ -38,11 +38,11 @@ export class PreUninstallCommand implements ICommand { } private async handleFeedbackForm(): Promise { - // disabled for now (6/24/2020) + // disabled for now (6/24/2020) // if (isInteractive()) { // this.$opener.open(PreUninstallCommand.FEEDBACK_FORM_URL); - // } - return Promise.resolve(); + // } + return Promise.resolve(); } } diff --git a/lib/common/test/unit-tests/preuninstall.ts b/lib/common/test/unit-tests/preuninstall.ts index 0d257f5265..b5438fc6ac 100644 --- a/lib/common/test/unit-tests/preuninstall.ts +++ b/lib/common/test/unit-tests/preuninstall.ts @@ -135,7 +135,7 @@ describe("preuninstall", () => { assert.isTrue(isClearInspectorCacheCalled, "When uninstall is called, `clearInspectorCache` method must be called"); }); - // disabled (6/24/2020) + // disabled (6/24/2020) // it("opens the uninstall feedback form when terminal is interactive and uninstall is called", async () => { // helpers.doesCurrentNpmCommandMatch = () => true; // helpers.isInteractive = () => true;