cavendish 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +103 -0
  3. data/.circleci/setup-rubygems.sh +3 -0
  4. data/.editorconfig +24 -0
  5. data/.gitignore +12 -0
  6. data/.rspec +3 -0
  7. data/.rubocop.yml +496 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +11 -0
  10. data/Gemfile +7 -0
  11. data/Gemfile.lock +143 -0
  12. data/Guardfile +5 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +82 -0
  15. data/Rakefile +1 -0
  16. data/bin/console +14 -0
  17. data/bin/setup +8 -0
  18. data/cavendish.gemspec +33 -0
  19. data/exe/cavendish +8 -0
  20. data/lib/cavendish.rb +13 -0
  21. data/lib/cavendish/assets/.circleci/config.yml +93 -0
  22. data/lib/cavendish/assets/.eslintrc.json +43 -0
  23. data/lib/cavendish/assets/.node-version +1 -0
  24. data/lib/cavendish/assets/App.jsx +12 -0
  25. data/lib/cavendish/assets/README.md.erb +59 -0
  26. data/lib/cavendish/assets/src/navigators/HomeNavigator.jsx +17 -0
  27. data/lib/cavendish/assets/src/screens/HomeScreen.jsx.erb +16 -0
  28. data/lib/cavendish/assets/src/screens/__specs__/HomeScreen.spec.js.erb +22 -0
  29. data/lib/cavendish/assets/src/utils/tailwindRn.js +7 -0
  30. data/lib/cavendish/assets/tailwind.config.js +8 -0
  31. data/lib/cavendish/cli.rb +53 -0
  32. data/lib/cavendish/commands/add_ci_config.rb +16 -0
  33. data/lib/cavendish/commands/add_eslint.rb +33 -0
  34. data/lib/cavendish/commands/add_react_navigation.rb +45 -0
  35. data/lib/cavendish/commands/add_readme.rb +15 -0
  36. data/lib/cavendish/commands/add_tailwind.rb +31 -0
  37. data/lib/cavendish/commands/add_testing.rb +81 -0
  38. data/lib/cavendish/commands/base.rb +9 -0
  39. data/lib/cavendish/commands/configure_git.rb +22 -0
  40. data/lib/cavendish/commands/create_expo_project.rb +20 -0
  41. data/lib/cavendish/config.rb +18 -0
  42. data/lib/cavendish/utils.rb +74 -0
  43. data/lib/cavendish/version.rb +5 -0
  44. metadata +260 -0
@@ -0,0 +1,43 @@
1
+ {
2
+ "env": {
3
+ "es6": true,
4
+ "jest": true
5
+ },
6
+ "extends": "airbnb",
7
+ "globals": {
8
+ "Atomics": "readonly",
9
+ "SharedArrayBuffer": "readonly",
10
+ "jest": true
11
+ },
12
+ "parser": "babel-eslint",
13
+ "parserOptions": {
14
+ "ecmaFeatures": {
15
+ "jsx": true
16
+ },
17
+ "ecmaVersion": 2018,
18
+ "sourceType": "module"
19
+ },
20
+ "plugins": ["react"],
21
+ "rules": {
22
+ "no-console": 2,
23
+ "react/prop-types": ["error", { "ignore": ["route", "navigation"] }],
24
+ "react/jsx-first-prop-new-line": [1, "multiline"],
25
+ "react/jsx-max-props-per-line": [1, { "maximum": 1 }],
26
+ "react/jsx-one-expression-per-line": "off",
27
+ "global-require": "off",
28
+ "import/prefer-default-export": "off",
29
+ "import/no-extraneous-dependencies": [
30
+ "error",
31
+ { "devDependencies": ["**/*.spec.js", "src/factories/**"] }
32
+ ],
33
+ "react/jsx-filename-extension": [1, { "extensions": [".spec.js", ".jsx"] }],
34
+ "react/jsx-props-no-spreading": 0
35
+ },
36
+ "settings": {
37
+ "import/resolver": {
38
+ "alias": {
39
+ "extensions": [".js", ".jsx"]
40
+ }
41
+ }
42
+ }
43
+ }
@@ -0,0 +1 @@
1
+ 14
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { NavigationContainer } from '@react-navigation/native';
3
+
4
+ import HomeNavigator from './src/navigators/HomeNavigator';
5
+
6
+ export default function App() {
7
+ return (
8
+ <NavigationContainer>
9
+ <HomeNavigator />
10
+ </NavigationContainer>
11
+ );
12
+ }
@@ -0,0 +1,59 @@
1
+ # <%= @config.human_project_name %>
2
+
3
+ This is a React Native + Expo application, initially generated using [Cavendish](https://github.com/platanus/cavendish) by Platanus.
4
+
5
+ ## Instalation and development
6
+
7
+ Assuming you've cloned the repo and that you have [Node](https://nodejs.org/en/) and [Yarn](https://yarnpkg.com/), the first thing you need to install is the Expo CLI:
8
+
9
+ ```bash
10
+ yarn global add expo-cli@4.8.x
11
+ ```
12
+
13
+ Then install the project dependencies in your local machine:
14
+
15
+ ```bash
16
+ yarn install
17
+ ```
18
+
19
+ And you're ready to go! You can now run the project with `yarn start` and scan the QR shown in console with the [Expo Go App](https://expo.dev/client). Remember that your phone and laptop have to be connected to the same wi-fi network in order for this to work!
20
+
21
+ ## Continuous Integration and deployment
22
+
23
+ The project has a setup to run tests and style guides in CircleCI. You can also run the test locally simulating the production environment using [CircleCI's method](https://circleci.com/docs/2.0/local-cli/).
24
+
25
+ The CI workflow also takes care of deploying and [publishing your application to Expo](https://docs.expo.io/workflow/publishing/). In order for this to work, you need to:
26
+
27
+ 1. Create a new account in [Expo](https://expo.dev/)
28
+ 1. [_Optional_] Create an [organization](https://docs.expo.io/accounts/account-types/#creating-new-organizations)
29
+ 1. Create an [access token](https://docs.expo.io/accounts/programmatic-access/)
30
+ 1. Configure the token as a [CircleCI environment variable](https://circleci.com/docs/2.0/env-vars/)
31
+
32
+ And you are done! Each time there is a commit in master, the pipeline will try to deploy the application.
33
+
34
+ If it succeeds, you will be able to scan and share the app QR code through `https://expo.io/@organization-or-user-name/<%= @config.project_name %>`.
35
+
36
+ ## Style Guides
37
+
38
+ Style guides are enforced through a CircleCI [job](.circleci/config.yml) with [reviewdog](https://github.com/reviewdog/reviewdog) as a reporter, using per-project dependencies and style configurations.
39
+
40
+ Please note that this reviewdog implementation requires a GitHub user token to comment on pull requests. A token can be generated [here](https://github.com/settings/tokens), and it should have at least the `repo` option checked.
41
+
42
+ The included `config.yml` assumes your CircleCI organization has a context named `org-global` with the required token under the environment variable `REVIEWDOG_GITHUB_API_TOKEN`.
43
+
44
+ The project comes bundled with configuration files available in this repository. You can add or modify rules by editing the [`.eslintrc.json`](.eslintrc.json) file.
45
+
46
+ You can (and should) use linter integrations for your text editor of choice, using the project's configuration.
47
+
48
+ ## Internal Dependencies
49
+
50
+ ### Tailwind RN
51
+ We use the TailwindCSS adaptation for React Native: [`tailwind-rn`](https://github.com/vadimdemedes/tailwind-rn), in order to reduce the friction in mobile apps styling.
52
+
53
+ If you need to add custom styles, make sure you follow the instructions given in the package's README.
54
+
55
+ ### React Navigation
56
+ We use [React Navigation](https://reactnavigation.org/)@<%= Cavendish::REACT_NAVIGATION_VERSION %> to handle the shown screens and navigation interactions of the application.
57
+
58
+ ### Testing
59
+ We use [Jest](https://jestjs.io/) and [React Native Testing Library](https://testing-library.com/docs/react-native-testing-library/intro/) in order to test the components of this app.
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { createStackNavigator } from '@react-navigation/stack';
3
+
4
+ import HomeScreen from '../screens/HomeScreen';
5
+
6
+ const Stack = createStackNavigator();
7
+
8
+ export default function HomeNavigator() {
9
+ return (
10
+ <Stack.Navigator>
11
+ <Stack.Screen
12
+ name="Home"
13
+ component={HomeScreen}
14
+ />
15
+ </Stack.Navigator>
16
+ );
17
+ }
@@ -0,0 +1,16 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Text } from 'react-native';
3
+
4
+ import tailwind from '../utils/tailwindRn';
5
+
6
+ export default function HomeScreen() {
7
+ const [projectName] = useState('<%= @config.human_project_name %>');
8
+
9
+ return (
10
+ <View style={tailwind('p-4 bg-gray-900 flex-1 justify-center items-center')}>
11
+ <Text style={tailwind('text-white')}>
12
+ Hello {projectName}!
13
+ </Text>
14
+ </View>
15
+ );
16
+ }
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ <% if @config.use_enzyme? %>
3
+ import { shallow } from 'enzyme';
4
+ import HomeScreen from '../HomeScreen';
5
+
6
+ describe('HomeScreen specs', () => {
7
+ it('shows application name', () => {
8
+ const component = shallow(<HomeScreen />);
9
+ expect(component.contains('<%= @config.human_project_name %>')).toBe(true);
10
+ });
11
+ });
12
+ <% else %>
13
+ import { render } from '@testing-library/react-native';
14
+ import HomeScreen from '../HomeScreen';
15
+
16
+ describe('HomeScreen specs', () => {
17
+ it('shows application name', () => {
18
+ const component = render(<HomeScreen />);
19
+ expect(component.queryByText('Hello <%= @config.human_project_name %>!')).not.toBeNull();
20
+ });
21
+ });
22
+ <% end %>
@@ -0,0 +1,7 @@
1
+ import { create } from 'tailwind-rn';
2
+ import styles from '../../styles.json';
3
+
4
+ const { tailwind, getColor } = create(styles);
5
+
6
+ export { getColor };
7
+ export default tailwind;
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ theme: {
3
+ extend: {},
4
+ },
5
+ variants: {
6
+ extend: {},
7
+ },
8
+ };
@@ -0,0 +1,53 @@
1
+ module Cavendish
2
+ class CLI
3
+ include Commander::Methods
4
+
5
+ def run
6
+ config = Cavendish::Config.new
7
+ define_program
8
+ define_create_command(config)
9
+ run!
10
+ end
11
+
12
+ private
13
+
14
+ def define_program
15
+ program :name, 'Cavendish'
16
+ program :version, Cavendish::VERSION
17
+ program :description, 'React Native + Expo project generator for Platanus'
18
+ end
19
+
20
+ def define_create_command(config)
21
+ command('create') do |c|
22
+ c.syntax = 'cavendish create'
23
+ c.description = 'Create a new React Native + Expo project'
24
+ c.action do |args|
25
+ setup_config(config, args)
26
+ create_command_steps.each { |command| command.for(config: config) }
27
+ end
28
+ end
29
+ end
30
+
31
+ def create_command_steps
32
+ [
33
+ Cavendish::Commands::CreateExpoProject,
34
+ Cavendish::Commands::AddTailwind,
35
+ Cavendish::Commands::AddReactNavigation,
36
+ Cavendish::Commands::AddEslint,
37
+ Cavendish::Commands::AddTesting,
38
+ Cavendish::Commands::AddCiConfig,
39
+ Cavendish::Commands::AddReadme,
40
+ Cavendish::Commands::ConfigureGit
41
+ ]
42
+ end
43
+
44
+ def setup_config(config, args)
45
+ config.project_name = args.first
46
+ config.testing_library = choose(
47
+ 'Which testing library would you like to use?',
48
+ 'Enzyme (unit orientated library)',
49
+ '@testing-library/react-native (integration orientated library)'
50
+ )
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,16 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddCiConfig < Cavendish::Commands::Base
4
+ def perform
5
+ copy_ci_and_version_files
6
+ end
7
+
8
+ private
9
+
10
+ def copy_ci_and_version_files
11
+ copy_file(".circleci/config.yml", ".circleci/config.yml")
12
+ copy_file(".node-version", ".node-version")
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddEslint < Cavendish::Commands::Base
4
+ def perform
5
+ copy_config_file
6
+ install_eslint_dependencies
7
+ end
8
+
9
+ private
10
+
11
+ def copy_config_file
12
+ copy_file(".eslintrc.json", ".eslintrc.json")
13
+ end
14
+
15
+ def install_eslint_dependencies
16
+ run_in_project("yarn add -D #{eslint_dependencies.join(' ')}")
17
+ end
18
+
19
+ def eslint_dependencies
20
+ %w[
21
+ babel-eslint
22
+ eslint
23
+ eslint-config-airbnb
24
+ eslint-import-resolver-alias
25
+ eslint-plugin-import
26
+ eslint-plugin-jsx-a11y
27
+ eslint-plugin-react
28
+ eslint-plugin-react-hooks
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,45 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddReactNavigation < Cavendish::Commands::Base
4
+ def perform
5
+ install_dependencies
6
+ add_example_navigator_and_screens
7
+ replace_app_entrypoint
8
+ end
9
+
10
+ private
11
+
12
+ def install_dependencies
13
+ run_in_project("yarn add #{react_navigation_core_dependencies.join(' ')}")
14
+ run_in_project("expo install #{react_navigation_side_dependencies.join(' ')}")
15
+ end
16
+
17
+ def add_example_navigator_and_screens
18
+ copy_template('src/screens/HomeScreen.jsx', 'src/screens/HomeScreen.jsx')
19
+ copy_file('src/navigators/HomeNavigator.jsx', 'src/navigators/HomeNavigator.jsx')
20
+ end
21
+
22
+ def replace_app_entrypoint
23
+ remove_in_project('App.js')
24
+ copy_file('App.jsx', 'App.jsx')
25
+ end
26
+
27
+ def react_navigation_core_dependencies
28
+ [
29
+ "@react-navigation/native@#{Cavendish::REACT_NAVIGATION_VERSION}",
30
+ "@react-navigation/stack@#{Cavendish::REACT_NAVIGATION_VERSION}"
31
+ ]
32
+ end
33
+
34
+ def react_navigation_side_dependencies
35
+ %w[
36
+ react-native-gesture-handler
37
+ react-native-reanimated
38
+ react-native-screens
39
+ react-native-safe-area-context
40
+ @react-native-community/masked-view
41
+ ]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddReadme < Cavendish::Commands::Base
4
+ def perform
5
+ parse_and_copy_file
6
+ end
7
+
8
+ private
9
+
10
+ def parse_and_copy_file
11
+ copy_template('README.md', 'README.md')
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddTailwind < Cavendish::Commands::Base
4
+ def perform
5
+ install_tailwind_rn_dependencies
6
+ copy_tailwind_config_file
7
+ generate_tailwind_rn_styles_json
8
+ copy_tailwind_utils
9
+ end
10
+
11
+ private
12
+
13
+ def install_tailwind_rn_dependencies
14
+ run_in_project('yarn add tailwind-rn')
15
+ run_in_project('yarn add -D tailwindcss')
16
+ end
17
+
18
+ def copy_tailwind_config_file
19
+ copy_file('tailwind.config.js', 'tailwind.config.js')
20
+ end
21
+
22
+ def generate_tailwind_rn_styles_json
23
+ run_in_project('yarn run create-tailwind-rn')
24
+ end
25
+
26
+ def copy_tailwind_utils
27
+ copy_file('src/utils/tailwindRn.js', 'src/utils/tailwindRn.js')
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,81 @@
1
+ module Cavendish
2
+ module Commands
3
+ class AddTesting < Cavendish::Commands::Base
4
+ def perform
5
+ install_dependencies
6
+ add_config_to_package
7
+ @config.use_enzyme? ? add_enzyme_options : add_rn_testing_library_options
8
+ add_example_test_file
9
+ end
10
+
11
+ private
12
+
13
+ def install_dependencies
14
+ run_in_project("yarn add -D #{jest_dependencies.join(' ')}")
15
+ end
16
+
17
+ def add_config_to_package
18
+ inject_to_json_file('package.json', package_configuration)
19
+ end
20
+
21
+ def add_enzyme_options
22
+ run_in_project("yarn add -D #{enzyme_dependencies.join(' ')}")
23
+ inject_to_json_file('package.json', enzyme_configuration)
24
+ end
25
+
26
+ def add_rn_testing_library_options
27
+ run_in_project("yarn add -D #{rn_testing_library_dependencies.join(' ')}")
28
+ end
29
+
30
+ def add_example_test_file
31
+ copy_template(
32
+ 'src/screens/__specs__/HomeScreen.spec.js',
33
+ 'src/screens/__specs__/HomeScreen.spec.js'
34
+ )
35
+ end
36
+
37
+ def jest_dependencies
38
+ %w[
39
+ jest
40
+ fishery
41
+ jest-expo
42
+ ]
43
+ end
44
+
45
+ def rn_testing_library_dependencies
46
+ %w[
47
+ @testing-library/jest-dom
48
+ @testing-library/react-native
49
+ ]
50
+ end
51
+
52
+ def enzyme_dependencies
53
+ %w[
54
+ enzyme
55
+ enzyme-adapter-react-16
56
+ jest-enzyme
57
+ jest-environment-enzyme
58
+ ]
59
+ end
60
+
61
+ def package_configuration
62
+ {
63
+ scripts: { test: 'jest' },
64
+ jest: {
65
+ preset: 'jest-expo',
66
+ transform: { '^.+\\.[jt]sx?$': 'babel-jest' }
67
+ }
68
+ }
69
+ end
70
+
71
+ def enzyme_configuration
72
+ {
73
+ jest: {
74
+ setupFilesAfterEnv: ['jest-enzyme'],
75
+ testEnvironment: 'enzyme'
76
+ }
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end