pep 0.0.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 (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/pep +11 -0
  3. data/lib/pep.rb +444 -0
  4. metadata +45 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cb620804258e340e261d0df726df127f78663a014c8cfe64c448129be06f9f64
4
+ data.tar.gz: c04defde77e88500b647bac8f4efc2b14188e339192b391f01593b599c2bdabe
5
+ SHA512:
6
+ metadata.gz: d58eb26fe8c45db760085bedb618717f9bf5f607cef1634f148e409e45a7ff28e7b1d3f1eb590c1ab439711596905f5600ece2c00a4cbbbc2be70e0d90fe7c6d
7
+ data.tar.gz: ad446d955b066874fdc4b508e9e083671dfd858fa6ee941a4a1cdc2705607f0331705498c127147d52448419cd7f31244f257cb0585160d48ae0bb48a0e587f4
data/bin/pep ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "pep"
4
+
5
+ first_cli_arg = ARGV[0]
6
+ if !first_cli_arg
7
+ puts "Usage: pep your-apps-name"
8
+ exit
9
+ end
10
+
11
+ run_pep(with_app_name: first_cli_arg)
data/lib/pep.rb ADDED
@@ -0,0 +1,444 @@
1
+ require "json"
2
+
3
+ module NeaHelpers
4
+ def self.add_development_dependency(dependency_name)
5
+ system("yarn add -D #{dependency_name}")
6
+ system("yarn install")
7
+ end
8
+
9
+ def self.add_dependency(dependency_name)
10
+ system("npx expo install #{dependency_name}")
11
+ end
12
+
13
+ def self.git_commit(with_message:)
14
+ system("git add .")
15
+ system("git commit -am '#{with_message}'")
16
+ end
17
+
18
+ def self.add_package_json_script(name:, script:)
19
+ package_json = JSON.parse(File.read("package.json"))
20
+ package_json["scripts"][name] = script
21
+ File.open("package.json", "w+") do |file|
22
+ file.write(JSON.pretty_generate(package_json))
23
+ end
24
+ end
25
+ end
26
+
27
+ class CreateTypescriptExpoApp
28
+ def self.create_typescript_expo_app(with_name:)
29
+ new(with_name).create_typescript_expo_app
30
+ end
31
+
32
+ attr_reader :app_name
33
+
34
+ def initialize(app_name)
35
+ @app_name = app_name
36
+ end
37
+
38
+ def create_typescript_expo_app
39
+ system("yarn create expo-app #{app_name} --template blank-typescript")
40
+ end
41
+ end
42
+
43
+ class AddPrettier
44
+ def self.add_prettier(to_app_with_name:)
45
+ new(to_app_with_name).add_prettier
46
+ end
47
+
48
+ attr_reader :app_name
49
+
50
+ def initialize(app_name)
51
+ @app_name = app_name
52
+ end
53
+
54
+ def add_prettier
55
+ Dir.chdir(app_name) do
56
+ write_prettier_rc
57
+ NeaHelpers.add_development_dependency("prettier")
58
+ NeaHelpers.add_package_json_script(
59
+ name: "prettier-check",
60
+ script: "prettier --check './**/*.{ts,tsx}'",
61
+ )
62
+ NeaHelpers.add_package_json_script(
63
+ name: "prettier-fix",
64
+ script: "prettier --write './**/*.{ts,tsx}'",
65
+ )
66
+ system("yarn prettier-fix")
67
+ NeaHelpers.git_commit(with_message: "Add prettier")
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def write_prettier_rc
74
+ File.open(".prettierrc", "w") do |prettier_rc|
75
+ prettier_rc.write(prettier_rc_content)
76
+ end
77
+ end
78
+
79
+ def prettier_rc_content
80
+ <<~EOS
81
+ {
82
+ "printWidth": 80,
83
+ "tabWidth": 2,
84
+ "useTabs": false,
85
+ "semi": false,
86
+ "singleQuote": false,
87
+ "quoteProps": "consistent",
88
+ "jsxSingleQuote": false,
89
+ "trailingComma": "all",
90
+ "bracketSpacing": true,
91
+ "bracketSameLine": false,
92
+ "arrowParens": "avoid",
93
+ "requirePragma": false,
94
+ "insertPragma": false,
95
+ "proseWrap": "preserve",
96
+ "endOfLine": "lf",
97
+ "embeddedLanguageFormatting": "auto",
98
+ "singleAttributePerLine": false
99
+ }
100
+ EOS
101
+ end
102
+ end
103
+
104
+ class ConfigureTypescript
105
+ def self.configure_typescript(in_app_with_name:)
106
+ new(in_app_with_name).configure_typescript
107
+ end
108
+
109
+ attr_reader :app_name
110
+
111
+ def initialize(app_name)
112
+ @app_name = app_name
113
+ end
114
+
115
+ def configure_typescript
116
+ Dir.chdir(app_name) do
117
+ update_tsconfig_json
118
+ NeaHelpers.add_package_json_script(name: "tsc", script: "tsc")
119
+ NeaHelpers.git_commit(with_message: "Configure typescript")
120
+ end
121
+ end
122
+
123
+ private
124
+
125
+ def update_tsconfig_json
126
+ tsconfig_json = JSON.parse(File.read("tsconfig.json"))
127
+ tsconfig_json_compiler_options.each do |name, value|
128
+ tsconfig_json["compilerOptions"][name] = value
129
+ end
130
+ File.open("tsconfig.json", "w+") do |file|
131
+ file.write(JSON.pretty_generate(tsconfig_json))
132
+ end
133
+ end
134
+
135
+ def tsconfig_json_compiler_options
136
+ {
137
+ "allowJs" => true,
138
+ "esModuleInterop" => true,
139
+ "jsx" => "react-native",
140
+ "lib" => ["DOM", "ESNext"],
141
+ "moduleResolution" => "node",
142
+ "noEmit" => true,
143
+ "resolveJsonModule" => true,
144
+ "skipLibCheck" => true,
145
+ "target" => "ESNext",
146
+ }
147
+ end
148
+ end
149
+
150
+ class AddEslint
151
+ def self.add_eslint(to_app_with_name:)
152
+ new(to_app_with_name).add_eslint
153
+ end
154
+
155
+ attr_reader :app_name
156
+
157
+ def initialize(app_name)
158
+ @app_name = app_name
159
+ end
160
+
161
+ def add_eslint
162
+ Dir.chdir(app_name) do
163
+ eslint_development_dependencies.each do |eslint_dev_dep|
164
+ NeaHelpers.add_development_dependency(eslint_dev_dep)
165
+ end
166
+ File.open(".eslintrc.js", "w+") do |file|
167
+ file.write(eslintrc_js_content)
168
+ end
169
+ NeaHelpers.add_package_json_script(
170
+ name: "lint",
171
+ script: "eslint '**/*.{ts,tsx}'",
172
+ )
173
+ NeaHelpers.git_commit(with_message: "Add eslint")
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def eslint_development_dependencies
180
+ [
181
+ "@typescript-eslint/eslint-plugin",
182
+ "@typescript-eslint/parser",
183
+ "eslint",
184
+ "eslint-plugin-react",
185
+ "eslint-plugin-react-hooks",
186
+ "eslint-plugin-react-native",
187
+ ]
188
+ end
189
+
190
+ def eslintrc_js_content
191
+ <<~EOS
192
+ module.exports = {
193
+ root: true,
194
+ parser: "@typescript-eslint/parser",
195
+ plugins: ["react", "react-native", "@typescript-eslint", "react-hooks"],
196
+ extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
197
+ parserOptions: {
198
+ ecmaFeatures: {
199
+ jsx: true,
200
+ },
201
+ project: "tsconfig.json",
202
+ },
203
+ env: {
204
+ "react-native/react-native": true,
205
+ },
206
+ rules: {
207
+ "react-native/no-unused-styles": 2,
208
+ "react-native/split-platform-components": 2,
209
+ "react-native/no-single-element-style-arrays": 2,
210
+ "react-hooks/rules-of-hooks": "error",
211
+ "react-hooks/exhaustive-deps": "error",
212
+ "@typescript-eslint/switch-exhaustiveness-check": "error",
213
+ "@typescript-eslint/ban-ts-comment": 0,
214
+ "@typescript-eslint/no-empty-function": 0,
215
+ },
216
+ }
217
+ EOS
218
+ end
219
+ end
220
+
221
+ class SetSrcAsRootDirectory
222
+ def self.set_src_as_root_directory(in_app_with_name:)
223
+ new(in_app_with_name).set_src_as_root_directory
224
+ end
225
+
226
+ attr_reader :app_name
227
+
228
+ def initialize(app_name)
229
+ @app_name = app_name
230
+ end
231
+
232
+ def set_src_as_root_directory
233
+ Dir.chdir(app_name) do
234
+ update_eslintrc
235
+ update_babel_config_js
236
+ move_app_tsx
237
+ update_tsconfig_json
238
+ NeaHelpers.git_commit(
239
+ with_message: "Set /src as the root directory for app code",
240
+ )
241
+ end
242
+ end
243
+
244
+ private
245
+
246
+ def update_tsconfig_json
247
+ package_json = JSON.parse(File.read("tsconfig.json"))
248
+ package_json["compilerOptions"]["baseUrl"] = "src"
249
+ File.open("tsconfig.json", "w+") do |file|
250
+ file.write(JSON.pretty_generate(package_json))
251
+ end
252
+ end
253
+
254
+ def move_app_tsx
255
+ system("mkdir src")
256
+ system("mv App.tsx src/")
257
+ File.open("./App.tsx", "w+") do |file|
258
+ file.write(
259
+ <<~EOS
260
+ import App from "./src/App"
261
+
262
+ export default App
263
+ EOS
264
+ )
265
+ end
266
+ end
267
+
268
+ def update_babel_config_js
269
+ new_content = new_babel_config_js_content
270
+ File.open("babel.config.js", "w+") do |file|
271
+ file.write(new_content)
272
+ end
273
+ end
274
+
275
+ def new_babel_config_js_content
276
+ current_lines = File.read("babel.config.js").split("\n")
277
+ current_lines.inject([]) do |lines, current_line|
278
+ if current_line == " return {"
279
+ lines + [current_line] + new_babel_config_js_lines
280
+ else
281
+ lines + [current_line]
282
+ end
283
+ end.join("\n")
284
+ end
285
+
286
+ def new_babel_config_js_lines
287
+ [
288
+ " plugins: [",
289
+ " [",
290
+ " \"module-resolver\",",
291
+ " {",
292
+ " root: [\"./src\"],",
293
+ " extensions: [\".ts\", \".tsx\"],",
294
+ " },",
295
+ " ],",
296
+ " ],",
297
+ ]
298
+ end
299
+
300
+ def update_eslintrc
301
+ new_content = new_eslintrc_content
302
+ File.open(".eslintrc.js", "w+") do |file|
303
+ file.write(new_content)
304
+ end
305
+ end
306
+
307
+ def new_eslintrc_content
308
+ current_lines = File.read(".eslintrc.js").split("\n")
309
+ new_lines = (
310
+ current_lines[0..-2] + new_eslintrc_lines + [current_lines[-1]]
311
+ ).join("\n")
312
+ end
313
+
314
+ def new_eslintrc_lines
315
+ [
316
+ " settings: {",
317
+ " \"import/resolver\": {",
318
+ " node: {",
319
+ " paths: [\"src\"],",
320
+ " },",
321
+ " },",
322
+ " },",
323
+ ]
324
+ end
325
+ end
326
+
327
+ class InstallReactNavigation
328
+ def self.install_react_navigation(in_app_with_name:)
329
+ new(in_app_with_name).install_react_navigation
330
+ end
331
+
332
+ attr_reader :app_name
333
+
334
+ def initialize(app_name)
335
+ @app_name = app_name
336
+ end
337
+
338
+ def install_react_navigation
339
+ Dir.chdir(app_name) do
340
+ install_dependencies
341
+ write_app_tsx
342
+ NeaHelpers.git_commit(with_message: "Add react navigation")
343
+ end
344
+ end
345
+
346
+ private
347
+
348
+ def write_app_tsx
349
+ File.open("./src/App.tsx", "w+") do |app_tsx|
350
+ app_tsx.write(app_tsx_content)
351
+ end
352
+ end
353
+
354
+ def install_dependencies
355
+ [
356
+ "@react-navigation/native",
357
+ "react-native-screens",
358
+ "react-native-safe-area-context",
359
+ "@react-navigation/native-stack",
360
+ ].each do |dep|
361
+ NeaHelpers.add_dependency(dep)
362
+ end
363
+ end
364
+
365
+ def app_tsx_content
366
+ <<~EOS
367
+ import { Button, Text, TextInput, View } from "react-native"
368
+ import { DefaultTheme, NavigationContainer } from "@react-navigation/native"
369
+ import { createNativeStackNavigator } from "@react-navigation/native-stack"
370
+ import type { NativeStackScreenProps } from "@react-navigation/native-stack"
371
+ import { useState } from "react"
372
+
373
+ type StackNavigatorParams = {
374
+ Home: undefined
375
+ Details: { homeScreensTextInputValue: string }
376
+ }
377
+
378
+ type HomeProps = NativeStackScreenProps<StackNavigatorParams, "Home">
379
+ type DetailsProps = NativeStackScreenProps<StackNavigatorParams, "Details">
380
+
381
+ const HomeScreen = ({ navigation }: HomeProps) => {
382
+ const [homeScreensTextInputValue, setHomescreensTextInputValue] =
383
+ useState<string>("")
384
+ return (
385
+ <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
386
+ <Text>Home Screen</Text>
387
+ <TextInput
388
+ value={homeScreensTextInputValue}
389
+ onChangeText={setHomescreensTextInputValue}
390
+ placeholder="Type somethin here dawg"
391
+ style={{ width: "50%", height: 50 }}
392
+ />
393
+ <Button
394
+ title="Go to Details"
395
+ onPress={() =>
396
+ navigation.navigate("Details", { homeScreensTextInputValue })
397
+ }
398
+ />
399
+ </View>
400
+ )
401
+ }
402
+
403
+ const DetailsScreen = ({ route }: DetailsProps) => {
404
+ const { homeScreensTextInputValue } = route.params
405
+ return (
406
+ <View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
407
+ <Text>Details Screen says: {homeScreensTextInputValue}</Text>
408
+ </View>
409
+ )
410
+ }
411
+
412
+ const Stack = createNativeStackNavigator<StackNavigatorParams>()
413
+
414
+ const MyTheme = {
415
+ ...DefaultTheme,
416
+ colors: {
417
+ ...DefaultTheme.colors,
418
+ background: "#fff",
419
+ },
420
+ }
421
+
422
+ const App = () => (
423
+ <NavigationContainer theme={MyTheme}>
424
+ <Stack.Navigator>
425
+ <Stack.Screen name="Home" component={HomeScreen} />
426
+ <Stack.Screen name="Details" component={DetailsScreen} />
427
+ </Stack.Navigator>
428
+ </NavigationContainer>
429
+ )
430
+
431
+ export default App
432
+ EOS
433
+ end
434
+ end
435
+
436
+ def run_pep(with_app_name:)
437
+ app_name = with_app_name
438
+ CreateTypescriptExpoApp.create_typescript_expo_app(with_name: app_name)
439
+ AddPrettier.add_prettier(to_app_with_name: app_name)
440
+ ConfigureTypescript.configure_typescript(in_app_with_name: app_name)
441
+ AddEslint.add_eslint(to_app_with_name: app_name)
442
+ SetSrcAsRootDirectory.set_src_as_root_directory(in_app_with_name: app_name)
443
+ InstallReactNavigation.install_react_navigation(in_app_with_name: app_name)
444
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pep
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick Pachulski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-03-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Start your expo app with prettier, typescript, eslint, and react navigation.
14
+ email: nick@pachulski.me
15
+ executables:
16
+ - pep
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/pep
21
+ - lib/pep.rb
22
+ homepage: https://rubygems.org/gems/pep
23
+ licenses:
24
+ - MIT
25
+ metadata: {}
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubygems_version: 3.4.8
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: Expo app scaffolding
45
+ test_files: []