diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index b2095be..0000000
--- a/.prettierrc
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "semi": false,
- "singleQuote": true
-}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 91d3abc..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-language: node_js
-
-node_js:
- - node
-
-cache:
- yarn: true
- directories:
- - node_modules
-
-install:
- - yarn
-
-script:
- - yarn test
-
-before_deploy:
- - yarn build
-
-deploy:
- skip_cleanup: true
- provider: npm
- email: $EMAIL
- api_key:
- secure: $API_KEY
- on:
- tags: true
- repo: somadevs/neutron
diff --git a/README.md b/README.md
index c11549f..ce129d7 100644
--- a/README.md
+++ b/README.md
@@ -1,62 +1,58 @@
-
-
-
-
- The best tool to speed up your development process! 💻️
-
-
+## 🚀 Overview
-[![npm](https://img.shields.io/npm/v/@somadevs/neutron.svg)](https://www.npmjs.com/package/@somadevs/neutron)
-[![Build Status](https://travis-ci.org/somadevs/neutron.svg?branch=master)](https://travis-ci.org/somadevs/neutron)
+This CLI was developed to help developers create new react projects with [Redux](https://github.com/reduxjs/redux) + [Duck Pattern](https://github.com/erikras/ducks-modular-redux).
-
+#### Templates and Scaffolding
-## Overview
+- [x] React JS
+- [x] React Native
-This CLI was developed to help developers create new projects quickly and easily.
+
-#### Templates and Scaffold
-
-- [x] ReactJS
-- [ ] React Native
-- [ ] Node REST API
-- [ ] Node GraphQL API
-
-## Quick Start
+## 👨🏽💻 Quick Start
To install Neutron CLI, execute into your terminal:
```shell
-$ npm i @somadevs/neutron -g
+# yarn
+$ yarn global add @neutron.js/cli
+
+# npm
+$ npm i @neutron.js/cli -g
```
Command list:
```shell
-$ neutron -h
-
- neutron -
- react add:component Add new component files
- react add:duck Add new duck file
- react add:page Add new page files
- react add:saga Add new saga file
- react create Create new react app with duck pattern
- help (h) -
- version (v) Output the version number
+Starts With:
+ neutron create Create new project with React
+
+Commands:
+ neutron add:component Add new component files
+ neutron add:duck Add new duck file
+ neutron add:page Add new page files
+ neutron add:saga Add new saga file
+
+Utils:
+ neutron -h Show help information
+ neutron -v Output the version number
```
-## What's under the hood?
+
+
+## 🚘 What's under the hood?
-⭐ [create-react-app](https://github.com/facebook/create-react-app) to create a project basis
⭐ [gluegun](https://github.com/infinitered/gluegun) toolkit for building node-based command-line interfaces
-## Contributing
+
+
+## 📃 Contributing
Thanks for your interest on our project. Take a moment to read our guidelines:
- [Contributing](.github/CONTRIBUTING.md)
- [Code of Conduct](.github/CODE_OF_CONDUCT.md)
-## License
+## 📃 License
-MIT © [Somadevs](https://github.com/somadevs)
+MIT © [NeutronJs](https://github.com/neutronjs)
diff --git a/__tests__/react/add-component.spec.ts b/__tests__/react/add-component.spec.ts
deleted file mode 100644
index e1d3c5f..0000000
--- a/__tests__/react/add-component.spec.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { filesystem } from 'gluegun'
-import { cli } from '../utils'
-
-test('should be add a new component', async () => {
- const name = 'ComponentName'
-
- await cli(`react add:component ${name}`)
-
- const index = filesystem.read(`__tests__/src/components/${name}/index.js`)
- expect(index).toContain(name)
-
- const styles = filesystem.read(`__tests__/src/components/${name}/styles.js`)
- expect(styles).toContain('Container')
-
- filesystem.remove('__tests__/src/components')
-})
diff --git a/__tests__/react/add-duck.spec.ts b/__tests__/react/add-duck.spec.ts
deleted file mode 100644
index 40a876a..0000000
--- a/__tests__/react/add-duck.spec.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { filesystem, strings } from 'gluegun'
-import { cli } from '../utils'
-
-test('should be add a new duck', async () => {
- const name = 'DuckName'
-
- await cli(`react add:duck ${name}`)
-
- const duck = filesystem.read(
- `__tests__/src/store/ducks/${strings.camelCase(name)}.js`
- )
- expect(duck).toContain(strings.pascalCase(name))
- expect(duck).toContain(strings.upperCase(name).replace(' ', '_'))
-
- filesystem.remove('__tests__/src/store/ducks')
-})
diff --git a/__tests__/react/add-page.spec.ts b/__tests__/react/add-page.spec.ts
deleted file mode 100644
index 7624609..0000000
--- a/__tests__/react/add-page.spec.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { filesystem } from 'gluegun'
-import { cli } from '../utils'
-
-test('should be add a new page', async () => {
- const name = 'PageName'
-
- await cli(`react add:page ${name}`)
-
- const index = filesystem.read(`__tests__/src/pages/${name}/index.js`)
- expect(index).toContain(name)
-
- const styles = filesystem.read(`__tests__/src/pages/${name}/styles.js`)
- expect(styles).toContain('Container')
-
- filesystem.remove('__tests__/src/pages')
-})
diff --git a/__tests__/react/add-saga.spec.ts b/__tests__/react/add-saga.spec.ts
deleted file mode 100644
index be878ee..0000000
--- a/__tests__/react/add-saga.spec.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { filesystem, strings } from 'gluegun'
-import { cli } from '../utils'
-
-test('should be add a new saga', async () => {
- const name = 'SagaName'
-
- await cli(`react add:saga ${name}`)
-
- const saga = filesystem.read(
- `__tests__/src/store/sagas/${strings.camelCase(name)}.js`
- )
- expect(saga).toContain(strings.pascalCase(name))
-
- filesystem.remove('__tests__/src/store/sagas')
-})
diff --git a/__tests__/react/create.spec.ts b/__tests__/react/create.spec.ts
deleted file mode 100644
index 4819730..0000000
--- a/__tests__/react/create.spec.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { filesystem } from 'gluegun'
-import { cli } from '../utils'
-
-test('should be create a new react app', async () => {
- const output = await cli('react create myapp')
- expect(output).toContain(`The project was created. Let's Code!`)
-
- const myapp = filesystem.read('__tests__/myapp/package.json')
- expect(myapp).toContain(`"name": "myapp"`)
-
- filesystem.remove('__tests__/myapp')
-})
diff --git a/__tests__/utils/index.ts b/__tests__/utils/index.ts
deleted file mode 100644
index ec59b98..0000000
--- a/__tests__/utils/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { system, filesystem } from 'gluegun'
-
-const bin = filesystem.path(__dirname, '..', '..', 'bin')
-
-export const cli = async (value: string) => {
- let cmd = `cd __tests__ &&`
- cmd = `${cmd} node ${filesystem.path(bin, 'neutron')} ${value}`
-
- return system.run(cmd)
-}
diff --git a/assets/neutron.png b/assets/neutron.png
deleted file mode 100644
index 8759a96..0000000
Binary files a/assets/neutron.png and /dev/null differ
diff --git a/assets/neutron.svg b/assets/neutron.svg
new file mode 100644
index 0000000..f7ec88d
--- /dev/null
+++ b/assets/neutron.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
diff --git a/commitlint.config.js b/commitlint.config.js
index a4f4369..661d895 100644
--- a/commitlint.config.js
+++ b/commitlint.config.js
@@ -1,3 +1,3 @@
module.exports = {
- extends: ['@commitlint/config-conventional']
-}
+ extends: ["@commitlint/config-conventional"]
+};
diff --git a/jest.config.js b/jest.config.js
deleted file mode 100644
index 97d45f1..0000000
--- a/jest.config.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// For a detailed explanation regarding each configuration property, visit:
-// https://jestjs.io/docs/en/configuration.html
-
-module.exports = {
- bail: true,
- clearMocks: true,
- testMatch: ['**/__tests__/**/*.spec.+(ts|tsx|js)'],
- transform: {
- '^.+\\.(ts|tsx)$': 'ts-jest'
- },
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx']
-}
diff --git a/package.json b/package.json
index bd17748..189399f 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
- "name": "@somadevs/neutron",
+ "name": "@neutron.js/cli",
"description": "This CLI was developed to help developers create new projects quickly and easily",
- "version": "1.0.0",
+ "version": "2.0.0",
"main": "build/cli.js",
"license": "MIT",
"bin": {
@@ -12,23 +12,22 @@
"lint": "tslint -p .",
"compile": "tsc -p .",
"templatescopy": "rm -rf build/templates && yes | cp -rf src/templates build/templates",
- "build": "yarn format && yarn lint && yarn compile && yarn templatescopy",
- "test": "jest",
- "watch": "jest --watch"
+ "build": "yarn format && yarn lint && yarn compile && yarn templatescopy"
},
"author": {
"name": "Thiago de Souza",
"email": "email@thiagodesouza.com.br",
- "url": "https://www.thiagodesouza.com.br"
+ "url": "https://github.com/thiagodesouza"
},
"repository": {
"type": "git",
- "url": "https://github.com/somadevs/neutron"
+ "url": "https://github.com/neutronjs/neutron-cli"
},
"keywords": [
"neutron",
+ "expo",
"react",
- "somadevs",
+ "react-native",
"node",
"typescript",
"gluegun"
@@ -39,7 +38,6 @@
"build",
"LICENSE",
"readme.md",
- "docs",
"bin"
],
"jest": {
@@ -52,21 +50,21 @@
}
},
"dependencies": {
- "gluegun": "^3.3.0",
- "ts-node": "^8.2.0",
- "typescript": "^3.5.1"
+ "exec-sh": "^0.3.2",
+ "gluegun": "^3.3.3",
+ "ts-node": "^8.3.0",
+ "typescript": "^3.6.2"
},
"devDependencies": {
- "@commitlint/cli": "^8.0.0",
- "@commitlint/config-conventional": "^8.0.0",
- "@types/jest": "^24.0.13",
- "@types/node": "^12.0.4",
- "husky": "^2.3.0",
- "jest": "^24.8.0",
- "prettier": "^1.12.1",
+ "@commitlint/cli": "^8.1.0",
+ "@commitlint/config-conventional": "^8.1.0",
+ "@types/jest": "^24.0.18",
+ "@types/node": "^12.7.2",
+ "husky": "^3.0.4",
+ "prettier": "^1.18.2",
"ts-jest": "^24.0.2",
- "tslint": "^5.12.0",
- "tslint-config-prettier": "^1.17.0",
+ "tslint": "^5.19.0",
+ "tslint-config-prettier": "^1.18.0",
"tslint-config-standard": "^8.0.1"
}
-}
+}
\ No newline at end of file
diff --git a/src/cli.ts b/src/cli.ts
index bc9cf4d..89e0cdf 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -1,4 +1,4 @@
-const { build } = require('gluegun')
+const { build } = require("gluegun");
/**
* Create the cli and kick it off
@@ -6,19 +6,17 @@ const { build } = require('gluegun')
async function run(argv) {
// create a CLI runtime
const cli = build()
- .brand('neutron')
+ .brand("neutron")
.src(__dirname)
- .plugins('./node_modules', { matching: 'neutron-*', hidden: true })
- .help() // provides default for help, h, --help, -h
+ .plugins("./node_modules", { matching: "neutron-*", hidden: true })
.version() // provides default for version, v, --version, -v
- .defaultCommand()
- .create()
+ .create();
// and run it
- const toolbox = await cli.run(argv)
+ const toolbox = await cli.run(argv);
// send it back (for testing, mostly)
- return toolbox
+ return toolbox;
}
-module.exports = { run }
+module.exports = { run };
diff --git a/src/commands/add-component.ts b/src/commands/add-component.ts
new file mode 100644
index 0000000..715ec33
--- /dev/null
+++ b/src/commands/add-component.ts
@@ -0,0 +1,73 @@
+import { GluegunToolbox } from "gluegun";
+import { GetCurrentPlatform, Platform, GetSettings } from "../settings";
+import {
+ MessageType,
+ PrintMessage,
+ PrintDivider,
+ PrintInvalidOperation
+} from "../tools/terminal";
+
+class HelpInfo {
+ static Message: string = "Usage: neutron add:component ";
+}
+
+class AddComponentCommand {
+ public name: string = "add:component";
+
+ public async run(toolbox: GluegunToolbox) {
+ const { commandName, parameters, template, filesystem, strings } = toolbox;
+
+ if (GetCurrentPlatform() === Platform.INVALID) {
+ PrintInvalidOperation();
+ return;
+ }
+
+ if (!parameters.options.h && parameters.first) {
+ const settings = GetSettings(commandName);
+
+ if (!parameters.first) {
+ PrintMessage(`The component name is not provided`, MessageType.ERROR);
+ return;
+ }
+
+ const name = strings.pascalCase(parameters.first);
+ const path = `src/components/${name}`;
+
+ if (filesystem.exists(path)) {
+ PrintMessage(
+ `This component already exists: ${name}`,
+ MessageType.ERROR
+ );
+ return;
+ }
+
+ const files: string[] = settings.template.files;
+ let generators: Promise[] = [];
+
+ generators = files.reduce((acc, file) => {
+ const gen = template.generate({
+ template: `${settings.template.path}/${file}`,
+ target: `${path}/${file.replace(".ejs", "")}`,
+ props: { name }
+ });
+ return acc.concat([gen]);
+ }, generators);
+
+ PrintMessage(
+ `Creating new component: "${path}" ...`,
+ MessageType.DEFAULT
+ );
+
+ await Promise.all(generators);
+
+ PrintDivider();
+ PrintMessage(`A new component was created!`, MessageType.SUCCESS);
+
+ return;
+ }
+
+ PrintMessage(HelpInfo.Message, MessageType.INFO);
+ }
+}
+
+export default new AddComponentCommand();
diff --git a/src/commands/add-duck.ts b/src/commands/add-duck.ts
new file mode 100644
index 0000000..7834470
--- /dev/null
+++ b/src/commands/add-duck.ts
@@ -0,0 +1,72 @@
+import { GluegunToolbox } from "gluegun";
+import { GetCurrentPlatform, Platform } from "../settings";
+import {
+ MessageType,
+ PrintMessage,
+ PrintDivider,
+ PrintInvalidOperation
+} from "../tools/terminal";
+
+class HelpInfo {
+ static Message: string = "Usage: neutron add:duck ";
+}
+
+class AddDuckCommand {
+ public name: string = "add:duck";
+
+ public async run(toolbox: GluegunToolbox) {
+ const {
+ parameters,
+ template,
+ filesystem,
+ strings
+ }: GluegunToolbox = toolbox;
+
+ if (GetCurrentPlatform() === Platform.INVALID) {
+ PrintInvalidOperation();
+ return;
+ }
+
+ if (!parameters.options.h && parameters.first) {
+ if (!parameters.first) {
+ PrintMessage(`The duck name is not provided`, MessageType.ERROR);
+ return;
+ }
+
+ const pascalCaseName = strings.pascalCase(parameters.first);
+ const camelCaseName = strings.camelCase(parameters.first);
+ const upperCaseName = strings.upperCase(pascalCaseName).replace(" ", "_");
+ const file = `src/store/ducks/${camelCaseName}.js`;
+
+ if (filesystem.exists(file)) {
+ PrintMessage(`This duck already exists: ${file}`, MessageType.ERROR);
+ return;
+ }
+
+ PrintMessage(`Creating new duck: "${file}" ...`, MessageType.DEFAULT);
+
+ await template.generate({
+ template: "shared/add-duck/duck.js.ejs",
+ target: file,
+ props: { pascalCaseName, upperCaseName }
+ });
+
+ PrintDivider();
+ PrintMessage(
+ 'A new duck was created! Please, add duck reference into "src/store/ducks/index.js":',
+ MessageType.SUCCESS
+ );
+ PrintMessage(
+ `import { reducer as ${camelCaseName} } from './${camelCaseName}';`,
+ MessageType.DEFAULT,
+ 2
+ );
+
+ return;
+ }
+
+ PrintMessage(HelpInfo.Message, MessageType.INFO);
+ }
+}
+
+export default new AddDuckCommand();
diff --git a/src/commands/add-page.ts b/src/commands/add-page.ts
new file mode 100644
index 0000000..834f89d
--- /dev/null
+++ b/src/commands/add-page.ts
@@ -0,0 +1,69 @@
+import { GluegunToolbox } from "gluegun";
+import { GetCurrentPlatform, Platform, GetSettings } from "../settings";
+import {
+ MessageType,
+ PrintMessage,
+ PrintDivider,
+ PrintInvalidOperation
+} from "../tools/terminal";
+
+class HelpInfo {
+ static Message: string = "Usage: neutron add:page ";
+}
+
+class AddPageCommand {
+ public name: string = "add:page";
+
+ public async run(toolbox: GluegunToolbox) {
+ const { commandName, parameters, template, filesystem, strings } = toolbox;
+
+ if (GetCurrentPlatform() === Platform.INVALID) {
+ PrintInvalidOperation();
+ return;
+ }
+
+ if (!parameters.options.h && parameters.first) {
+ const settings = GetSettings(commandName);
+
+ if (!parameters.first) {
+ PrintMessage(`The page name is not provided`, MessageType.ERROR);
+ return;
+ }
+
+ const name = strings.pascalCase(parameters.first);
+ const path = `src/pages/${name}`;
+
+ if (filesystem.exists(path)) {
+ PrintMessage(`This page already exists: ${name}`, MessageType.ERROR);
+ return;
+ }
+
+ const files: string[] = settings.template.files;
+ let generators: Promise[] = [];
+
+ generators = files.reduce((acc, file) => {
+ const gen = template.generate({
+ template: `${settings.template.path}/${file}`,
+ target: `${path}/${file.replace(".ejs", "")}`,
+ props: { name }
+ });
+ return acc.concat([gen]);
+ }, generators);
+
+ PrintMessage(`Creating new files: "${path}" ...`, MessageType.DEFAULT);
+
+ await Promise.all(generators);
+
+ PrintDivider();
+ PrintMessage(
+ 'A new page was created! Please, add page reference into "src/routes/index.js".',
+ MessageType.SUCCESS
+ );
+ return;
+ }
+
+ PrintMessage(HelpInfo.Message, MessageType.INFO);
+ }
+}
+
+export default new AddPageCommand();
diff --git a/src/commands/add-saga.ts b/src/commands/add-saga.ts
new file mode 100644
index 0000000..e32f7b0
--- /dev/null
+++ b/src/commands/add-saga.ts
@@ -0,0 +1,77 @@
+import { GluegunToolbox } from "gluegun";
+import { GetCurrentPlatform, Platform } from "../settings";
+import {
+ MessageType,
+ PrintMessage,
+ PrintDivider,
+ PrintInvalidOperation
+} from "../tools/terminal";
+
+class HelpInfo {
+ static Message: string = "Usage: neutron add:saga ";
+}
+
+class AddSagaCommand {
+ public name: string = "add:saga";
+
+ public async run(toolbox: GluegunToolbox) {
+ const {
+ parameters,
+ template,
+ filesystem,
+ strings
+ }: GluegunToolbox = toolbox;
+
+ if (GetCurrentPlatform() === Platform.INVALID) {
+ PrintInvalidOperation();
+ return;
+ }
+
+ if (!parameters.options.h && parameters.first) {
+ if (!parameters.first) {
+ PrintMessage(`The saga name is not provided`, MessageType.ERROR);
+ return;
+ }
+
+ const name = strings.pascalCase(parameters.first);
+ const camelCaseName = strings.camelCase(parameters.first);
+
+ const file = `src/store/sagas/${camelCaseName}.js`;
+
+ if (filesystem.exists(file)) {
+ PrintMessage(`This saga already exists: ${file}`, MessageType.ERROR);
+ return;
+ }
+
+ PrintMessage(`Creating new saga: "${file}" ...`, MessageType.DEFAULT);
+
+ await template.generate({
+ template: "shared/add-saga/saga.js.ejs",
+ target: file,
+ props: { name, camelCaseName }
+ });
+
+ PrintDivider();
+ PrintMessage(
+ 'A new saga was created! Please, add saga reference into "src/store/sagas/index.js":',
+ MessageType.SUCCESS
+ );
+
+ PrintMessage(
+ `import { ${name}Types } from '../ducks/${camelCaseName}';`,
+ MessageType.DEFAULT,
+ 2
+ );
+ PrintMessage(
+ `import { add${name}Request } from './${camelCaseName}';`,
+ MessageType.DEFAULT,
+ 2
+ );
+ return;
+ }
+
+ PrintMessage(HelpInfo.Message, MessageType.INFO);
+ }
+}
+
+export default new AddSagaCommand();
diff --git a/src/commands/create.ts b/src/commands/create.ts
new file mode 100644
index 0000000..467478b
--- /dev/null
+++ b/src/commands/create.ts
@@ -0,0 +1,155 @@
+import { GluegunToolbox } from "gluegun";
+import { Platform, GetSettings } from "../settings";
+import { PackageManager } from "../tools/package-manager";
+import {
+ MessageType,
+ PrintMessage,
+ PrintNewLine,
+ PrintDivider
+} from "../tools/terminal";
+
+class HelpInfo {
+ static Message: string = "Usage: neutron create ";
+ static Options: any = {
+ Text: "Platforms:",
+ Rows: [
+ "--web New project with ReactJS",
+ "--mobile New project with React Native"
+ ]
+ };
+}
+
+class CreateCommand {
+ public name: string = "create";
+
+ public async run(toolbox: GluegunToolbox) {
+ const {
+ commandName,
+ parameters,
+ filesystem,
+ template,
+ system,
+ strings
+ } = toolbox;
+
+ if (!parameters.options.h && parameters.first) {
+ const { web, mobile } = parameters.options;
+
+ if (web !== mobile) {
+ const platformType = web ? Platform.WEB : Platform.MOBILE;
+ const settings = GetSettings(commandName, platformType);
+ const { first: appName } = parameters;
+ const pascalCaseAppName = strings.pascalCase(appName);
+ PrintDivider();
+
+ if (!appName) {
+ PrintMessage("The app name is not provided", MessageType.ERROR);
+ return;
+ }
+
+ if (Array.isArray(settings.requirements)) {
+ const requirementList: Array = [];
+
+ settings.requirements.forEach(requirement => {
+ if (!system.which(requirement)) {
+ requirementList.push(requirement);
+ }
+ });
+
+ if (requirementList.length > 0) {
+ PrintMessage("Global package required:", MessageType.ERROR);
+ requirementList.forEach(requirement => {
+ PrintMessage(`- ${requirement}`, MessageType.ERROR, 2);
+ });
+ return;
+ }
+ }
+
+ if (filesystem.exists(appName)) {
+ PrintMessage(
+ `The "${appName}" folder already exists.`,
+ MessageType.ERROR
+ );
+ return;
+ }
+
+ try {
+ PrintMessage(
+ "Creating App project structure...",
+ MessageType.DEFAULT
+ );
+
+ const files: string[] = settings.template.files;
+ let generators: Promise[] = [];
+
+ generators = files.reduce((acc, file) => {
+ const gen = template.generate({
+ template: `${settings.template.path}/${file}`,
+ target: `${appName}/${file.replace(".ejs", "")}`,
+ props: {
+ name: appName,
+ pascalCaseName: pascalCaseAppName
+ }
+ });
+
+ return acc.concat([gen]);
+ }, generators);
+
+ await Promise.all(generators);
+
+ const dependencies: string[] = settings.install.dependencies;
+ const devDependencies: string[] = settings.install.devDependencies;
+ const packageManager = new PackageManager();
+
+ PrintNewLine();
+ PrintMessage(
+ "Installing packages required by your application in production...",
+ MessageType.INFO
+ );
+ await packageManager.install(appName, dependencies, false);
+
+ PrintNewLine();
+ PrintMessage(
+ "Installing packages that are only needed for local development and testing...",
+ MessageType.INFO
+ );
+ await packageManager.install(appName, devDependencies, true);
+
+ PrintNewLine();
+ PrintMessage(
+ "The project was created successfuly!",
+ MessageType.SUCCESS
+ );
+ PrintDivider();
+ PrintNewLine();
+
+ const manager = system.which("yarn") ? "yarn" : "npm run";
+
+ PrintMessage(
+ "We suggest that you begin by typing:",
+ MessageType.DEFAULT
+ );
+ PrintNewLine();
+ PrintMessage(`$ cd ${appName}`, MessageType.DEFAULT, 2);
+ PrintMessage(`$ ${manager} start`, MessageType.DEFAULT, 2);
+ PrintNewLine();
+ PrintDivider();
+ return;
+ } catch (err) {
+ PrintMessage(err, MessageType.ERROR);
+ return;
+ }
+ }
+ }
+
+ PrintMessage(HelpInfo.Message, MessageType.INFO);
+ PrintNewLine();
+
+ PrintMessage(HelpInfo.Options.Text, MessageType.DEFAULT);
+ HelpInfo.Options.Rows.forEach(row => {
+ PrintMessage(row, MessageType.DEFAULT, 2);
+ });
+ }
+}
+
+export default new CreateCommand();
diff --git a/src/commands/neutron.ts b/src/commands/neutron.ts
new file mode 100644
index 0000000..63dd657
--- /dev/null
+++ b/src/commands/neutron.ts
@@ -0,0 +1,99 @@
+import { GluegunToolbox } from "gluegun";
+import {
+ MessageType,
+ PrintMessage,
+ PrintNewLine,
+ PrintDivider
+} from "../tools/terminal";
+
+const { version } = require("../../package.json");
+
+class NeutronInfo {
+ public static Header = {
+ Title: [
+ String.raw` _ _ _ _ ____ `,
+ String.raw`|:\ | | ___ _ _|:|_ _ __ ___ _ __ | /:___| `,
+ String.raw`| \| |/ _ \ | | | __| '__/ _ \| '_ \ _ | \___ \ `,
+ String.raw`| |\ | __/ |_| | |_| | | (_) | | | |:|_| |___) |`,
+ String.raw`|_| \_|\___|\__,_|\__|_| \___/|_| |_|\___/|____/ `
+ ],
+ SubTitle: `React & React Native Flux Architecture CLI v${version}`
+ };
+ public static HelpInfo = {
+ StartsWith: {
+ Text: "Starts With:",
+ Rows: ["neutron create Create new project with React"]
+ },
+ Commands: {
+ Text: "Commands:",
+ Rows: [
+ "neutron add:component Add new component files",
+ "neutron add:duck Add new duck file",
+ "neutron add:page Add new page files",
+ "neutron add:saga Add new saga file"
+ ]
+ },
+ Utils: {
+ Text: "Utils:",
+ Rows: [
+ "neutron -h Show help information",
+ "neutron -v Output the version number"
+ ]
+ }
+ };
+ public static Footer = {
+ Text: "For more information:",
+ Link: "https://www.neutronjs.com"
+ };
+}
+
+class NeutronCommand {
+ public name: string = "neutron";
+
+ public async run(toolbox: GluegunToolbox) {
+ const { parameters }: GluegunToolbox = toolbox;
+ const { Header, HelpInfo, Footer } = NeutronInfo;
+
+ PrintNewLine();
+ PrintDivider();
+ Header.Title.forEach(line => {
+ PrintMessage(line, MessageType.DEFAULT);
+ });
+ PrintNewLine();
+ PrintMessage(Header.SubTitle, MessageType.SUCCESS);
+ PrintNewLine();
+ PrintDivider();
+ PrintNewLine();
+
+ if (parameters.options.h) {
+ const { StartsWith, Commands, Utils } = HelpInfo;
+
+ PrintMessage(StartsWith.Text, MessageType.DEFAULT);
+ StartsWith.Rows.forEach(line => {
+ PrintMessage(line, MessageType.DEFAULT, 2);
+ });
+ PrintNewLine();
+
+ PrintMessage(Commands.Text, MessageType.DEFAULT);
+ Commands.Rows.forEach(line => {
+ PrintMessage(line, MessageType.DEFAULT, 2);
+ });
+ PrintNewLine();
+
+ PrintMessage(Utils.Text, MessageType.DEFAULT);
+ Utils.Rows.forEach(line => {
+ PrintMessage(line, MessageType.DEFAULT, 2);
+ });
+ PrintNewLine();
+ PrintDivider();
+ PrintNewLine();
+ }
+
+ PrintMessage(Footer.Text, MessageType.DEFAULT);
+ PrintMessage(Footer.Link, MessageType.INFO);
+ PrintNewLine();
+ PrintDivider();
+ }
+}
+
+export default new NeutronCommand();
diff --git a/src/commands/react/add-component.ts b/src/commands/react/add-component.ts
deleted file mode 100644
index 943a66e..0000000
--- a/src/commands/react/add-component.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { GluegunToolbox } from 'gluegun'
-import { NeutronUtils } from '../../utils'
-
-module.exports = {
- name: 'add:component',
- description: 'Add new component files',
- run: async (toolbox: GluegunToolbox) => {
- const { parameters, template, filesystem, strings } = toolbox
- const { terminal } = new NeutronUtils(toolbox)
-
- if (!parameters.first) {
- terminal.error(`The component name is not provided`)
- return
- }
-
- const name = strings.pascalCase(parameters.first)
- const path = `src/components/${name}`
-
- if (filesystem.exists(path)) {
- terminal.error(`This component already exists: ${name}`)
- return
- }
-
- const files: string[] = ['index.js.ejs', 'styles.js.ejs']
-
- let generators: Promise[] = []
-
- generators = files.reduce((prev, file) => {
- const gen = template.generate({
- template: `react/add-component/${file}`,
- target: `${path}/${file.replace('.ejs', '')}`,
- props: { name }
- })
- return prev.concat([gen])
- }, generators)
-
- await Promise.all(generators)
-
- terminal.info(`Creating new component: "${path}" ...`)
- terminal.success('A new component was created!')
- }
-}
diff --git a/src/commands/react/add-duck.ts b/src/commands/react/add-duck.ts
deleted file mode 100644
index 969043d..0000000
--- a/src/commands/react/add-duck.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { GluegunToolbox } from 'gluegun'
-import { NeutronUtils } from '../../utils'
-
-module.exports = {
- name: 'add:duck',
- description: 'Add new duck file',
- run: async (toolbox: GluegunToolbox) => {
- const { parameters, template, filesystem, strings } = toolbox
- const { terminal } = new NeutronUtils(toolbox)
-
- if (!parameters.first) {
- terminal.error(`The duck name is not provided`)
- return
- }
-
- const pascalCaseName = strings.pascalCase(parameters.first)
- const camelCaseName = strings.camelCase(parameters.first)
- const upperCaseName = strings.upperCase(pascalCaseName).replace(' ', '_')
- const file = `src/store/ducks/${camelCaseName}.js`
-
- if (filesystem.exists(file)) {
- terminal.error(`This duck already exists: ${file}`)
- return
- }
-
- await template.generate({
- template: 'react/add-duck/duck.js.ejs',
- target: file,
- props: { pascalCaseName, upperCaseName }
- })
-
- terminal.info(`Creating new duck: "${file}" ...`)
- terminal.success(
- 'A new duck was created! Please, add duck reference into "src/store/ducks/index.js":'
- )
-
- terminal.info(
- ` import { reducer as ${camelCaseName} } from './${camelCaseName}';`
- )
- }
-}
diff --git a/src/commands/react/add-page.ts b/src/commands/react/add-page.ts
deleted file mode 100644
index 55e5330..0000000
--- a/src/commands/react/add-page.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GluegunToolbox } from 'gluegun'
-import { NeutronUtils } from '../../utils'
-
-module.exports = {
- name: 'add:page',
- description: 'Add new page files',
- run: async (toolbox: GluegunToolbox) => {
- const { parameters, template, filesystem, strings } = toolbox
- const { terminal } = new NeutronUtils(toolbox)
-
- if (!parameters.first) {
- terminal.error(`The page name is not provided`)
- return
- }
-
- const name = strings.pascalCase(parameters.first)
- const path = `src/pages/${name}`
-
- if (filesystem.exists(path)) {
- terminal.error(`This page already exists: ${name}`)
- return
- }
-
- const files: string[] = ['index.js.ejs', 'styles.js.ejs']
-
- let generators: Promise[] = []
-
- generators = files.reduce((prev, file) => {
- const gen = template.generate({
- template: `react/add-page/${file}`,
- target: `${path}/${file.replace('.ejs', '')}`,
- props: { name }
- })
- return prev.concat([gen])
- }, generators)
-
- await Promise.all(generators)
-
- terminal.info(`Creating new files: "${path}" ...`)
- terminal.success(
- 'A new page was created! Please, add page reference into "src/routes/index.js":'
- )
-
- terminal.info(` import ${name} from '../pages/${name}';`)
- terminal.info(' ...')
- terminal.info(
- ` `
- )
- }
-}
diff --git a/src/commands/react/add-saga.ts b/src/commands/react/add-saga.ts
deleted file mode 100644
index 56cd624..0000000
--- a/src/commands/react/add-saga.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { GluegunToolbox } from 'gluegun'
-import { NeutronUtils } from '../../utils'
-
-module.exports = {
- name: 'add:saga',
- description: 'Add new saga file',
- run: async (toolbox: GluegunToolbox) => {
- const { parameters, template, filesystem, strings } = toolbox
- const { terminal } = new NeutronUtils(toolbox)
-
- if (!parameters.first) {
- terminal.error(`The saga name is not provided`)
- return
- }
-
- const name = strings.pascalCase(parameters.first)
- const camelCaseName = strings.camelCase(parameters.first)
-
- const file = `src/store/sagas/${camelCaseName}.js`
-
- if (filesystem.exists(file)) {
- terminal.error(`This saga already exists: ${file}`)
- return
- }
-
- await template.generate({
- template: 'react/add-saga/saga.js.ejs',
- target: file,
- props: { name, camelCaseName }
- })
-
- terminal.info(`Creating new saga: "${file}" ...`)
- terminal.success(
- 'A new saga was created! Please, add saga reference into "src/store/sagas/index.js":'
- )
-
- terminal.info(` import { ${name}Types } from '../ducks/${camelCaseName}';`)
- terminal.info(` import { add${name}Request } from './${camelCaseName}';`)
- }
-}
diff --git a/src/commands/react/create.ts b/src/commands/react/create.ts
deleted file mode 100644
index 275b435..0000000
--- a/src/commands/react/create.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import { GluegunToolbox } from 'gluegun'
-import { NeutronUtils } from '../../utils'
-
-module.exports = {
- name: 'create',
- description: 'Create new react app with duck pattern',
- run: async (toolbox: GluegunToolbox) => {
- const { parameters, filesystem, template, system }: GluegunToolbox = toolbox
- const { terminal, packageManager } = new NeutronUtils(toolbox)
-
- const appName = parameters.first
-
- if (!appName) {
- terminal.error('The app name is not provided')
- return
- }
-
- if (filesystem.exists(appName)) {
- terminal.error(`The "${appName}" folder already exists.`)
- return
- }
-
- try {
- terminal.info('Creating App project structure...')
-
- const files: string[] = [
- 'public/favicon.ico.ejs',
- 'public/index.html.ejs',
- 'src/components/Hello/index.js.ejs',
- 'src/components/Hello/styles.js.ejs',
- 'src/config/reactotron.js.ejs',
- 'src/pages/Home/index.js.ejs',
- 'src/pages/Home/styles.js.ejs',
- 'src/routes/history.js.ejs',
- 'src/routes/index.js.ejs',
- 'src/services/api.js.ejs',
- 'src/store/index.js.ejs',
- 'src/store/ducks/index.js.ejs',
- 'src/store/sagas/index.js.ejs',
- 'src/styles/colors.js.ejs',
- 'src/styles/global.js.ejs',
- 'src/utils/notification.js.ejs',
- 'src/utils/storage.js.ejs',
- 'src/App.js.ejs',
- 'src/index.js.ejs',
- '.editorconfig.ejs',
- '.env.ejs',
- '.env.example.ejs',
- '.eslintrc.json.ejs',
- '.gitignore.ejs',
- 'commitlint.config.js.ejs',
- 'dockerfile.ejs',
- 'package.json.ejs',
- 'LICENSE.ejs',
- 'README.md.ejs'
- ]
-
- let generators: Promise[] = []
-
- generators = files.reduce((prev, file) => {
- const gen = template.generate({
- template: `react/create/${file}`,
- target: `${appName}/${file.replace('.ejs', '')}`,
- props: { name: appName }
- })
- return prev.concat([gen])
- }, generators)
-
- await Promise.all(generators)
-
- const { latest } = parameters.options
-
- if (latest) {
- try {
- const dependencies = [
- '@rocketseat/unform',
- 'axios',
- 'connected-react-router',
- 'dotenv',
- 'history',
- 'lodash',
- 'prop-types',
- 'react',
- 'react-dom',
- 'react-redux',
- 'react-router-dom',
- 'react-scripts',
- 'react-toastify',
- 'reactotron-react-js',
- 'reactotron-redux',
- 'reactotron-redux-saga',
- 'redux',
- 'redux-saga',
- 'redux-thunk',
- 'reduxsauce',
- 'seamless-immutable',
- 'styled-components',
- 'yup'
- ]
-
- const devDependencies = [
- '@commitlint/cli',
- '@commitlint/config-conventional',
- 'eslint',
- 'eslint-config-airbnb',
- 'eslint-plugin-import',
- 'eslint-plugin-jsx-a11y',
- 'eslint-plugin-react',
- 'eslint-plugin-react-hooks',
- 'husky'
- ]
-
- terminal.info(await packageManager.install(dependencies, false))
- terminal.info(await packageManager.install(devDependencies, false))
- } catch (err) {
- terminal.error(err)
- }
- }
-
- terminal.success(`The project was created. Let's Code!`, true)
-
- terminal.success(` $ cd ${appName}`)
- system.which('yarn')
- ? terminal.success(` $ yarn install`, true)
- : terminal.success(` $ npm install`, true)
- } catch (err) {
- terminal.error(err)
- }
- }
-}
diff --git a/src/settings/index.ts b/src/settings/index.ts
new file mode 100644
index 0000000..2b35711
--- /dev/null
+++ b/src/settings/index.ts
@@ -0,0 +1,45 @@
+import { filesystem } from "gluegun";
+import reactSettings from "./react";
+import reactNativeSettings from "./react-native";
+
+/**
+ * Platform enumerator
+ */
+export enum Platform {
+ INVALID,
+ MOBILE,
+ WEB
+}
+
+/**
+ * Get current project platform
+ */
+export function GetCurrentPlatform(): Platform {
+ const packageJson = filesystem.read("./package.json", "json");
+
+ if (packageJson) {
+ if ("react-native" in packageJson.dependencies) {
+ return Platform.MOBILE;
+ } else if ("react" in packageJson.dependencies) {
+ return Platform.WEB;
+ }
+ }
+ return Platform.INVALID;
+}
+
+/**
+ * Get platform settings
+ */
+export function GetSettings(
+ commandName: string,
+ platform: Platform = GetCurrentPlatform()
+) {
+ switch (platform) {
+ case Platform.MOBILE:
+ return reactNativeSettings[commandName];
+ case Platform.WEB:
+ return reactSettings[commandName];
+ default:
+ return null;
+ }
+}
diff --git a/src/settings/react-native/add-component.ts b/src/settings/react-native/add-component.ts
new file mode 100644
index 0000000..08d2861
--- /dev/null
+++ b/src/settings/react-native/add-component.ts
@@ -0,0 +1,6 @@
+export default {
+ template: {
+ path: "react-native/add-component",
+ files: ["index.js.ejs", "styles.js.ejs"]
+ }
+};
diff --git a/src/settings/react-native/add-page.ts b/src/settings/react-native/add-page.ts
new file mode 100644
index 0000000..c412fed
--- /dev/null
+++ b/src/settings/react-native/add-page.ts
@@ -0,0 +1,6 @@
+export default {
+ template: {
+ path: "react-native/add-page",
+ files: ["index.js.ejs", "styles.js.ejs"]
+ }
+};
diff --git a/src/settings/react-native/create.ts b/src/settings/react-native/create.ts
new file mode 100644
index 0000000..614bdfe
--- /dev/null
+++ b/src/settings/react-native/create.ts
@@ -0,0 +1,66 @@
+export default {
+ template: {
+ path: "react-native/create",
+ files: [
+ ".expo-shared/assets.json.ejs",
+ "assets/icon.png.ejs",
+ "assets/splash.png.ejs",
+ "src/components/Hello/index.js.ejs",
+ "src/components/Hello/styles.js.ejs",
+ "src/pages/Main/index.js.ejs",
+ "src/pages/Main/styles.js.ejs",
+ "src/services/api.js.ejs",
+ "src/store/ducks/index.js.ejs",
+ "src/store/sagas/index.js.ejs",
+ "src/store/index.js.ejs",
+ "src/styles/colors.js.ejs",
+ "src/styles/index.js.ejs",
+ "src/styles/metrics.js.ejs",
+ "src/utils/storage.js.ejs",
+ "src/index.js.ejs",
+ "src/routes.js.ejs",
+ ".editorconfig.ejs",
+ ".eslintrc.json.ejs",
+ ".gitignore.ejs",
+ ".watchmanconfig.ejs",
+ "App.js.ejs",
+ "app.json.ejs",
+ "babel.config.js.ejs",
+ "jsconfig.json.ejs",
+ "LICENSE.ejs",
+ "package.json.ejs",
+ "README.md.ejs"
+ ]
+ },
+ requirements: ["expo-cli"],
+ install: {
+ dependencies: [
+ "axios",
+ "expo",
+ "prop-types",
+ "react",
+ "react-dom",
+ "https://github.com/expo/react-native/archive/sdk-34.0.1.tar.gz",
+ "react-native-gesture-handler@~1.3.0",
+ "react-native-web",
+ "react-navigation",
+ "react-redux",
+ "redux",
+ "redux-saga",
+ "reduxsauce",
+ "seamless-immutable"
+ ],
+ devDependencies: [
+ "babel-eslint",
+ "babel-plugin-root-import",
+ "babel-preset-expo",
+ "eslint",
+ "eslint-config-airbnb",
+ "eslint-import-resolver-babel-plugin-root-import",
+ "eslint-plugin-import",
+ "eslint-plugin-jsx-a11y",
+ "eslint-plugin-react",
+ "eslint-plugin-react-native"
+ ]
+ }
+};
diff --git a/src/settings/react-native/index.ts b/src/settings/react-native/index.ts
new file mode 100644
index 0000000..bd9a790
--- /dev/null
+++ b/src/settings/react-native/index.ts
@@ -0,0 +1,9 @@
+import addComponent from "./add-component";
+import addPage from "./add-page";
+import create from "./create";
+
+export default {
+ "add:component": addComponent,
+ "add:page": addPage,
+ create: create
+};
diff --git a/src/settings/react/add-component.ts b/src/settings/react/add-component.ts
new file mode 100644
index 0000000..b6d5fa1
--- /dev/null
+++ b/src/settings/react/add-component.ts
@@ -0,0 +1,6 @@
+export default {
+ template: {
+ path: "react/add-component",
+ files: ["index.js.ejs", "styles.js.ejs"]
+ }
+};
diff --git a/src/settings/react/add-page.ts b/src/settings/react/add-page.ts
new file mode 100644
index 0000000..e3654ba
--- /dev/null
+++ b/src/settings/react/add-page.ts
@@ -0,0 +1,6 @@
+export default {
+ template: {
+ path: "react/add-page",
+ files: ["index.js.ejs", "styles.js.ejs"]
+ }
+};
diff --git a/src/settings/react/create.ts b/src/settings/react/create.ts
new file mode 100644
index 0000000..6f875e8
--- /dev/null
+++ b/src/settings/react/create.ts
@@ -0,0 +1,71 @@
+export default {
+ template: {
+ path: "react/create",
+ files: [
+ "public/favicon.ico.ejs",
+ "public/index.html.ejs",
+ "src/assets/images/neutron-logo.svg.ejs",
+ "src/components/Hello/index.js.ejs",
+ "src/components/Hello/styles.js.ejs",
+ "src/config/ReactotronConfig.js.ejs",
+ "src/pages/Home/index.js.ejs",
+ "src/pages/Home/styles.js.ejs",
+ "src/routes/history.js.ejs",
+ "src/routes/index.js.ejs",
+ "src/services/api.js.ejs",
+ "src/store/index.js.ejs",
+ "src/store/ducks/index.js.ejs",
+ "src/store/sagas/index.js.ejs",
+ "src/styles/colors.js.ejs",
+ "src/styles/global.js.ejs",
+ "src/utils/notification.js.ejs",
+ "src/utils/storage.js.ejs",
+ "src/App.js.ejs",
+ "src/index.js.ejs",
+ ".editorconfig.ejs",
+ ".eslintrc.json.ejs",
+ ".gitignore.ejs",
+ "commitlint.config.js.ejs",
+ "dockerfile.ejs",
+ "package.json.ejs",
+ "LICENSE.ejs",
+ "README.md.ejs"
+ ]
+ },
+ requirements: [],
+ install: {
+ dependencies: [
+ "axios",
+ "connected-react-router",
+ "history",
+ "lodash",
+ "prop-types",
+ "react",
+ "react-dom",
+ "react-redux",
+ "react-router-dom",
+ "react-scripts",
+ "react-toastify",
+ "reactotron-react-js",
+ "reactotron-redux",
+ "reactotron-redux-saga",
+ "redux",
+ "redux-saga",
+ "redux-thunk",
+ "reduxsauce",
+ "seamless-immutable",
+ "styled-components"
+ ],
+ devDependencies: [
+ "@commitlint/cli",
+ "@commitlint/config-conventional",
+ "eslint",
+ "eslint-config-airbnb",
+ "eslint-plugin-import",
+ "eslint-plugin-jsx-a11y",
+ "eslint-plugin-react",
+ "eslint-plugin-react-hooks",
+ "husky"
+ ]
+ }
+};
diff --git a/src/settings/react/index.ts b/src/settings/react/index.ts
new file mode 100644
index 0000000..bd9a790
--- /dev/null
+++ b/src/settings/react/index.ts
@@ -0,0 +1,9 @@
+import addComponent from "./add-component";
+import addPage from "./add-page";
+import create from "./create";
+
+export default {
+ "add:component": addComponent,
+ "add:page": addPage,
+ create: create
+};
diff --git a/src/templates/react-native/add-component/index.js.ejs b/src/templates/react-native/add-component/index.js.ejs
new file mode 100644
index 0000000..c7a440f
--- /dev/null
+++ b/src/templates/react-native/add-component/index.js.ejs
@@ -0,0 +1,12 @@
+import React from 'react';
+import { Text, View } from 'react-native';
+
+import styles from './styles';
+
+export default function <%= props.name %>() {
+ return (
+
+ Lala component!
+
+ );
+}
diff --git a/src/templates/react-native/add-component/styles.js.ejs b/src/templates/react-native/add-component/styles.js.ejs
new file mode 100644
index 0000000..3292932
--- /dev/null
+++ b/src/templates/react-native/add-component/styles.js.ejs
@@ -0,0 +1,18 @@
+import { StyleSheet } from 'react-native';
+import { colors, metrics } from '~/styles';
+
+export default StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ backgroundColor: colors.secundary,
+ borderRadius: metrics.baseRadius,
+ display: 'flex',
+ height: 100,
+ justifyContent: 'center',
+ width: 300,
+ },
+ title: {
+ fontSize: 24,
+ color: colors.lighter,
+ },
+});
diff --git a/src/templates/react-native/add-page/index.js.ejs b/src/templates/react-native/add-page/index.js.ejs
new file mode 100644
index 0000000..0487100
--- /dev/null
+++ b/src/templates/react-native/add-page/index.js.ejs
@@ -0,0 +1,20 @@
+import React, { useState, useEffect } from 'react';
+import { Text, View } from 'react-native';
+
+import styles from './styles';
+
+function <%= props.name %>() {
+ const [message, setMessage] = useState(null);
+
+ useEffect(() => {
+ setMessage('<%= props.name %> page!');
+ }, []);
+
+ return (
+
+ {message}
+
+ );
+}
+
+export default <%= props.name %>;
diff --git a/src/templates/react-native/add-page/styles.js.ejs b/src/templates/react-native/add-page/styles.js.ejs
new file mode 100644
index 0000000..2c4ca59
--- /dev/null
+++ b/src/templates/react-native/add-page/styles.js.ejs
@@ -0,0 +1,17 @@
+import { StyleSheet } from 'react-native';
+import { colors, metrics } from '~/styles';
+
+export default StyleSheet.create({
+ container: {
+ backgroundColor: colors.background,
+ color: colors.primary,
+ alignItems: 'center',
+ height: metrics.screenHeight,
+ width: metrics.screenWidth,
+ justifyContent: 'center',
+ },
+ title: {
+ fontSize: 24,
+ color: colors.lighter,
+ },
+});
diff --git a/src/templates/react-native/create/.editorconfig.ejs b/src/templates/react-native/create/.editorconfig.ejs
new file mode 100644
index 0000000..c6c8b36
--- /dev/null
+++ b/src/templates/react-native/create/.editorconfig.ejs
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
diff --git a/src/templates/react-native/create/.eslintrc.json.ejs b/src/templates/react-native/create/.eslintrc.json.ejs
new file mode 100644
index 0000000..65f97e0
--- /dev/null
+++ b/src/templates/react-native/create/.eslintrc.json.ejs
@@ -0,0 +1,39 @@
+{
+ "parser": "babel-eslint",
+ "env": {
+ "es6": true,
+ "jest": true
+ },
+ "extends": ["airbnb", "plugin:react-native/all"],
+ "globals": {
+ "Atomics": "readonly",
+ "SharedArrayBuffer": "readonly",
+ "__DEV__": true
+ },
+ "parserOptions": {
+ "ecmaFeatures": {
+ "jsx": true
+ },
+ "ecmaVersion": 2018,
+ "sourceType": "module"
+ },
+ "plugins": ["react", "react-native", "jsx-a11y", "import"],
+ "rules": {
+ "react/jsx-filename-extension": [
+ "error",
+ { "extensions": [".js", ".jsx"] }
+ ],
+ "import/prefer-default-export": "off",
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
+ "react/jsx-one-expression-per-line": "off",
+ "react-native/no-color-literals": "off",
+ "react-native/sort-styles": "off",
+ "global-require": "off",
+ "react-native/no-raw-text": "off"
+ },
+ "settings": {
+ "import/resolver": {
+ "babel-plugin-root-import": { "rootPathSuffix": "src" }
+ }
+ }
+}
diff --git a/src/templates/react-native/create/.expo-shared/assets.json.ejs b/src/templates/react-native/create/.expo-shared/assets.json.ejs
new file mode 100644
index 0000000..82254e1
--- /dev/null
+++ b/src/templates/react-native/create/.expo-shared/assets.json.ejs
@@ -0,0 +1,4 @@
+{
+ "f38ddefb22dda28452e95ae685df40c3360a44648fd870e1c92fe99d2f882865": true,
+ "e26c586094190db52f1735a99607376acb4040754fe4a6ea9e3f9db7439c6390": true
+}
\ No newline at end of file
diff --git a/src/templates/react-native/create/.gitignore.ejs b/src/templates/react-native/create/.gitignore.ejs
new file mode 100644
index 0000000..4820714
--- /dev/null
+++ b/src/templates/react-native/create/.gitignore.ejs
@@ -0,0 +1,11 @@
+node_modules/**/*
+.expo/*
+npm-debug.*
+*.jks
+*.p8
+*.p12
+*.key
+*.mobileprovision
+*.orig.*
+web-build/
+web-report/
diff --git a/src/templates/react-native/create/.watchmanconfig.ejs b/src/templates/react-native/create/.watchmanconfig.ejs
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/src/templates/react-native/create/.watchmanconfig.ejs
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/src/templates/react-native/create/App.js.ejs b/src/templates/react-native/create/App.js.ejs
new file mode 100644
index 0000000..3cc6bc7
--- /dev/null
+++ b/src/templates/react-native/create/App.js.ejs
@@ -0,0 +1,3 @@
+import App from './src';
+
+export default App;
diff --git a/src/templates/react-native/create/LICENSE.ejs b/src/templates/react-native/create/LICENSE.ejs
new file mode 100644
index 0000000..15bc72f
--- /dev/null
+++ b/src/templates/react-native/create/LICENSE.ejs
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/templates/react-native/create/README.md.ejs b/src/templates/react-native/create/README.md.ejs
new file mode 100644
index 0000000..9407be5
--- /dev/null
+++ b/src/templates/react-native/create/README.md.ejs
@@ -0,0 +1,9 @@
+# Neutron - React Native (Expo) Template
+
+This template was created to ease the development of new React Native projects.
+
+## Start application:
+
+```shell
+$ yarn start
+```
diff --git a/src/templates/react-native/create/app.json.ejs b/src/templates/react-native/create/app.json.ejs
new file mode 100644
index 0000000..a34f82f
--- /dev/null
+++ b/src/templates/react-native/create/app.json.ejs
@@ -0,0 +1,31 @@
+{
+ "expo": {
+ "name": "<%= props.pascalCaseName %>",
+ "slug": "<%= props.name %>",
+ "privacy": "public",
+ "sdkVersion": "34.0.0",
+ "platforms": [
+ "ios",
+ "android",
+ "web"
+ ],
+ "version": "1.0.0",
+ "orientation": "portrait",
+ "icon": "./assets/icon.png",
+ "splash": {
+ "image": "./assets/splash.png",
+ "resizeMode": "contain",
+ "backgroundColor": "#1f1e29"
+ },
+ "updates": {
+ "fallbackToCacheTimeout": 0
+ },
+ "assetBundlePatterns": [
+ "**/*"
+ ],
+ "ios": {
+ "supportsTablet": true
+ },
+ "description": ""
+ }
+}
\ No newline at end of file
diff --git a/src/templates/react-native/create/assets/icon.png.ejs b/src/templates/react-native/create/assets/icon.png.ejs
new file mode 100644
index 0000000..e7d701c
Binary files /dev/null and b/src/templates/react-native/create/assets/icon.png.ejs differ
diff --git a/src/templates/react-native/create/assets/splash.png.ejs b/src/templates/react-native/create/assets/splash.png.ejs
new file mode 100644
index 0000000..267b743
Binary files /dev/null and b/src/templates/react-native/create/assets/splash.png.ejs differ
diff --git a/src/templates/react-native/create/babel.config.js.ejs b/src/templates/react-native/create/babel.config.js.ejs
new file mode 100644
index 0000000..b99137a
--- /dev/null
+++ b/src/templates/react-native/create/babel.config.js.ejs
@@ -0,0 +1,14 @@
+module.exports = (api) => {
+ api.cache(true);
+ return {
+ presets: ['babel-preset-expo'],
+ plugins: [
+ [
+ 'babel-plugin-root-import',
+ {
+ rootPathSuffix: 'src',
+ },
+ ],
+ ],
+ };
+};
diff --git a/src/templates/react-native/create/jsconfig.json.ejs b/src/templates/react-native/create/jsconfig.json.ejs
new file mode 100644
index 0000000..56c62bf
--- /dev/null
+++ b/src/templates/react-native/create/jsconfig.json.ejs
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["src/*"]
+ }
+ }
+}
diff --git a/src/templates/react-native/create/package.json.ejs b/src/templates/react-native/create/package.json.ejs
new file mode 100644
index 0000000..4ab5d41
--- /dev/null
+++ b/src/templates/react-native/create/package.json.ejs
@@ -0,0 +1,12 @@
+{
+ "main": "node_modules/expo/AppEntry.js",
+ "scripts": {
+ "start": "expo start",
+ "android": "expo start --android",
+ "ios": "expo start --ios",
+ "web": "expo start --web",
+ "eject": "expo eject",
+ "lint": "eslint ."
+ },
+ "private": true
+}
\ No newline at end of file
diff --git a/src/templates/react-native/create/src/components/Hello/index.js.ejs b/src/templates/react-native/create/src/components/Hello/index.js.ejs
new file mode 100644
index 0000000..0cfeca5
--- /dev/null
+++ b/src/templates/react-native/create/src/components/Hello/index.js.ejs
@@ -0,0 +1,19 @@
+import React from 'react';
+import { Image, Text, View } from 'react-native';
+
+import styles from './styles';
+
+export default function Hello() {
+ return (
+
+
+ NeutronJS
+ React Native Template!
+
+ );
+}
diff --git a/src/templates/react-native/create/src/components/Hello/styles.js.ejs b/src/templates/react-native/create/src/components/Hello/styles.js.ejs
new file mode 100644
index 0000000..898e171
--- /dev/null
+++ b/src/templates/react-native/create/src/components/Hello/styles.js.ejs
@@ -0,0 +1,30 @@
+import { StyleSheet } from 'react-native';
+import { colors, metrics } from '~/styles';
+
+export default StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ backgroundColor: colors.secundary,
+ borderRadius: metrics.baseRadius,
+ display: 'flex',
+ height: 300,
+ justifyContent: 'center',
+ marginTop: metrics.screenHeight * 0.2,
+ width: 300,
+ },
+ logo: {
+ height: 150,
+ width: 150,
+ },
+ information: {
+ color: colors.lighter,
+ fontSize: 14,
+ marginTop: metrics.baseMargin * 2,
+ textAlign: 'center',
+ },
+ title: {
+ color: colors.lighter,
+ fontSize: 24,
+ textAlign: 'center',
+ },
+});
diff --git a/src/templates/react-native/create/src/index.js.ejs b/src/templates/react-native/create/src/index.js.ejs
new file mode 100644
index 0000000..916f50b
--- /dev/null
+++ b/src/templates/react-native/create/src/index.js.ejs
@@ -0,0 +1,13 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+import store from '~/store';
+
+import Routes from '~/routes';
+
+export default function App() {
+ return (
+
+
+
+ );
+}
diff --git a/src/templates/react-native/create/src/pages/Main/index.js.ejs b/src/templates/react-native/create/src/pages/Main/index.js.ejs
new file mode 100644
index 0000000..080f711
--- /dev/null
+++ b/src/templates/react-native/create/src/pages/Main/index.js.ejs
@@ -0,0 +1,13 @@
+import React from 'react';
+import { View } from 'react-native';
+
+import Hello from '~/components/Hello';
+import styles from './styles';
+
+const Main = () => (
+
+
+
+);
+
+export default Main;
diff --git a/src/templates/react-native/create/src/pages/Main/styles.js.ejs b/src/templates/react-native/create/src/pages/Main/styles.js.ejs
new file mode 100644
index 0000000..ad04267
--- /dev/null
+++ b/src/templates/react-native/create/src/pages/Main/styles.js.ejs
@@ -0,0 +1,11 @@
+import { StyleSheet } from 'react-native';
+import { colors } from '~/styles';
+
+export default StyleSheet.create({
+ container: {
+ alignItems: 'center',
+ backgroundColor: colors.background,
+ flex: 1,
+ paddingHorizontal: 20,
+ },
+});
diff --git a/src/templates/react-native/create/src/routes.js.ejs b/src/templates/react-native/create/src/routes.js.ejs
new file mode 100644
index 0000000..49f937a
--- /dev/null
+++ b/src/templates/react-native/create/src/routes.js.ejs
@@ -0,0 +1,7 @@
+import { createAppContainer, createSwitchNavigator } from 'react-navigation';
+
+import Main from '~/pages/Main';
+
+const Routes = createAppContainer(createSwitchNavigator({ Main }));
+
+export default Routes;
diff --git a/src/templates/react-native/create/src/services/api.js.ejs b/src/templates/react-native/create/src/services/api.js.ejs
new file mode 100644
index 0000000..c3787eb
--- /dev/null
+++ b/src/templates/react-native/create/src/services/api.js.ejs
@@ -0,0 +1,20 @@
+import axios from 'axios';
+import storage from '~/utils/storage';
+
+const api = axios.create({
+ baseURL: 'https://api.github.com',
+});
+
+api.interceptors.request.use(async (config) => {
+ const token = await storage.getToken();
+
+ const headers = { ...config.headers };
+
+ if (token) {
+ headers.Authorization = `Bearer ${token}`;
+ }
+
+ return { ...config, headers };
+});
+
+export default api;
diff --git a/src/templates/react-native/create/src/store/ducks/index.js.ejs b/src/templates/react-native/create/src/store/ducks/index.js.ejs
new file mode 100644
index 0000000..f907c4e
--- /dev/null
+++ b/src/templates/react-native/create/src/store/ducks/index.js.ejs
@@ -0,0 +1,9 @@
+import { combineReducers } from 'redux';
+
+// import { reducer as session } from './session';
+
+const reducers = combineReducers({
+ // session,
+});
+
+export default reducers;
diff --git a/src/templates/react-native/create/src/store/index.js.ejs b/src/templates/react-native/create/src/store/index.js.ejs
new file mode 100644
index 0000000..08fb873
--- /dev/null
+++ b/src/templates/react-native/create/src/store/index.js.ejs
@@ -0,0 +1,13 @@
+import { createStore, compose, applyMiddleware } from 'redux';
+import createSagaMiddleware from 'redux-saga';
+
+import reducers from './ducks';
+import sagas from './sagas';
+
+const sagaMiddleware = createSagaMiddleware();
+const middlewares = [sagaMiddleware];
+const store = createStore(reducers, compose(applyMiddleware(...middlewares)));
+
+sagaMiddleware.run(sagas);
+
+export default store;
diff --git a/src/templates/react-native/create/src/store/sagas/index.js.ejs b/src/templates/react-native/create/src/store/sagas/index.js.ejs
new file mode 100644
index 0000000..a3b04de
--- /dev/null
+++ b/src/templates/react-native/create/src/store/sagas/index.js.ejs
@@ -0,0 +1,10 @@
+import { all } from 'redux-saga/effects';
+
+// import { SessionTypes } from '../ducks/session';
+// import { addSessionRequest } from './session';
+
+export default function* rootSaga() {
+ yield all([
+ // takeLatest(SessionTypes.ADD_SESSION_REQUEST, addSessionRequest),
+ ]);
+}
diff --git a/src/templates/react-native/create/src/styles/colors.js.ejs b/src/templates/react-native/create/src/styles/colors.js.ejs
new file mode 100644
index 0000000..a5be75d
--- /dev/null
+++ b/src/templates/react-native/create/src/styles/colors.js.ejs
@@ -0,0 +1,17 @@
+export default {
+ white: '#fff',
+ lighter: '#eee',
+ light: '#ddd',
+ regular: '#999',
+ dark: '#666',
+ darker: '#333',
+ black: '#000',
+
+ primary: '#0078d4',
+ secundary: '#1f1e29',
+ background: '#14131a',
+
+ transparent: 'transparent',
+ blackTransparent: 'rgba(0,0,0,0.6)',
+ whiteTransparent: 'rgba(255,255,255, 0.3)',
+};
diff --git a/src/templates/react-native/create/src/styles/index.js.ejs b/src/templates/react-native/create/src/styles/index.js.ejs
new file mode 100644
index 0000000..37fd3f6
--- /dev/null
+++ b/src/templates/react-native/create/src/styles/index.js.ejs
@@ -0,0 +1,4 @@
+import colors from './colors';
+import metrics from './metrics';
+
+export { colors, metrics };
diff --git a/src/templates/react-native/create/src/styles/metrics.js.ejs b/src/templates/react-native/create/src/styles/metrics.js.ejs
new file mode 100644
index 0000000..06854c5
--- /dev/null
+++ b/src/templates/react-native/create/src/styles/metrics.js.ejs
@@ -0,0 +1,11 @@
+import { Dimensions } from 'react-native';
+
+const { width, height } = Dimensions.get('window');
+
+export default {
+ baseMargin: 10,
+ basePadding: 15,
+ baseRadius: 5,
+ screenWidth: width < height ? width : height,
+ screenHeight: height > width ? height : width,
+};
diff --git a/src/templates/react-native/create/src/utils/storage.js.ejs b/src/templates/react-native/create/src/utils/storage.js.ejs
new file mode 100644
index 0000000..784cbe2
--- /dev/null
+++ b/src/templates/react-native/create/src/utils/storage.js.ejs
@@ -0,0 +1,14 @@
+import { AsyncStorage } from 'react-native';
+
+const prefix = '@AppName:';
+
+const storageKeys = {
+ token: `${prefix}token`,
+};
+
+export default {
+ // Token
+ setToken: async (token) => AsyncStorage.setItem(storageKeys.token, token),
+ getToken: async () => AsyncStorage.getItem(storageKeys.token),
+ removeToken: async () => AsyncStorage.removeItem(storageKeys.token),
+};
diff --git a/src/templates/react/create/.env.ejs b/src/templates/react/create/.env.ejs
deleted file mode 100644
index 7892f35..0000000
--- a/src/templates/react/create/.env.ejs
+++ /dev/null
@@ -1 +0,0 @@
-REACT_APP_API_URL=http://localhost:3333
diff --git a/src/templates/react/create/.env.example.ejs b/src/templates/react/create/.env.example.ejs
deleted file mode 100644
index 7892f35..0000000
--- a/src/templates/react/create/.env.example.ejs
+++ /dev/null
@@ -1 +0,0 @@
-REACT_APP_API_URL=http://localhost:3333
diff --git a/src/templates/react/create/.eslintrc.json.ejs b/src/templates/react/create/.eslintrc.json.ejs
index 973d7c0..83886b1 100644
--- a/src/templates/react/create/.eslintrc.json.ejs
+++ b/src/templates/react/create/.eslintrc.json.ejs
@@ -1,18 +1,28 @@
{
"parser": "babel-eslint",
- "extends": "airbnb",
+ "extends": [
+ "airbnb"
+ ],
"env": {
"browser": true,
"jest": true
},
- "plugins": ["react", "jsx-a11y", "import"],
+ "plugins": [
+ "react",
+ "jsx-a11y",
+ "import"
+ ],
"rules": {
"react/jsx-filename-extension": [
"error",
{
- "extensions": [".js", ".jsx"]
+ "extensions": [
+ ".js",
+ ".jsx"
+ ]
}
],
+ "single-quote": "off",
"camelcase": "off",
"global-require": "off",
"import/prefer-default-export": "off",
@@ -21,7 +31,7 @@
"no-unused-vars": [
"error",
{
- "argsIgnorePatter": "^_"
+ "argsIgnorePattern": "^_"
}
]
}
diff --git a/src/templates/react/create/README.md.ejs b/src/templates/react/create/README.md.ejs
index 24e5a8b..47b4e39 100644
--- a/src/templates/react/create/README.md.ejs
+++ b/src/templates/react/create/README.md.ejs
@@ -2,21 +2,13 @@
This template was created to ease the development of new ReactJS projects.
-
-
-## How to Start Application?
-
-Create a `.env` file based into `.env.example` and run:
+## Start application:
```shell
-# install dependencies
-$ yarn || npm install
-
-# run application
$ yarn start || npm start
```
-To create a docker container, run:
+## Create docker container:
```shell
# create image
@@ -25,11 +17,3 @@ $ docker build -t your-image-name .
# run application (port: 3099)
$ docker run --name your-container-name -p 3099:3000 -d your-image-name
```
-
-
-
-Best regards,
-
-**Thiago Rodrigues de Souza** \
-**email:** email@thiagodesouza.com.br \
-**site:** [https://www.thiagodesouza.com.br](https://www.thiagodesouza.com.br)
diff --git a/src/templates/react/create/package.json.ejs b/src/templates/react/create/package.json.ejs
index 3bbd181..c64c7bd 100644
--- a/src/templates/react/create/package.json.ejs
+++ b/src/templates/react/create/package.json.ejs
@@ -28,41 +28,5 @@
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
- },
- "dependencies": {
- "@rocketseat/unform": "^1.5.1",
- "axios": "^0.19.0",
- "connected-react-router": "^6.4.0",
- "dotenv": "^8.0.0",
- "history": "^4.9.0",
- "lodash": "^4.17.11",
- "prop-types": "^15.7.2",
- "react": "^16.8.6",
- "react-dom": "^16.8.6",
- "react-redux": "^7.1.0",
- "react-router-dom": "^5.0.1",
- "react-scripts": "^3.0.1",
- "react-toastify": "^5.3.1",
- "reactotron-react-js": "^3.3.2",
- "reactotron-redux": "^3.1.1",
- "reactotron-redux-saga": "^4.2.2",
- "redux": "^4.0.1",
- "redux-saga": "^1.0.4",
- "redux-thunk": "^2.3.0",
- "reduxsauce": "^1.1.0",
- "seamless-immutable": "^7.1.4",
- "styled-components": "^4.3.2",
- "yup": "^0.27.0"
- },
- "devDependencies": {
- "@commitlint/cli": "^8.0.0",
- "@commitlint/config-conventional": "^8.0.0",
- "eslint": "^5.16.0",
- "eslint-config-airbnb": "^17.1.0",
- "eslint-plugin-import": "^2.18.0",
- "eslint-plugin-jsx-a11y": "^6.2.2",
- "eslint-plugin-react": "^7.14.2",
- "eslint-plugin-react-hooks": "^1.6.1",
- "husky": "^2.7.0"
}
}
diff --git a/src/templates/react/create/public/favicon.ico.ejs b/src/templates/react/create/public/favicon.ico.ejs
index 2d0a4ea..a11777c 100644
Binary files a/src/templates/react/create/public/favicon.ico.ejs and b/src/templates/react/create/public/favicon.ico.ejs differ
diff --git a/src/templates/react/create/public/index.html.ejs b/src/templates/react/create/public/index.html.ejs
index 3330e75..0cde337 100644
--- a/src/templates/react/create/public/index.html.ejs
+++ b/src/templates/react/create/public/index.html.ejs
@@ -1,10 +1,11 @@
-
-
-
-
-
-
- Neutron | ReactJS
-
-
- You need to enable JavaScript to run this app!
-
-
-
-
+