@highbeek/create-rnstarterkit 1.0.2-beta.12 → 1.0.2-beta.14

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.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # RNStarterKit
2
2
 
3
- **A CLI tool that scaffolds production-ready React Native apps with clean architecture and sensible defaults.**
3
+ **A CLI that scaffolds production-ready React Native apps with clean architecture and sensible defaults.**
4
4
 
5
- Not a replacement for Expo or React Native CLI — it sits on top of them and structures your project the right way from day one.
5
+ Not a replacement for Expo or React Native CLI — it sits on top of them and structures your project correctly from day one.
6
6
 
7
7
  ```bash
8
8
  npx @highbeek/create-rnstarterkit myApp
@@ -12,221 +12,199 @@ npx @highbeek/create-rnstarterkit myApp
12
12
 
13
13
  ## Why This Exists
14
14
 
15
- Every serious React Native project eventually ends up with the same architecture decisions:
15
+ Every serious React Native project ends up making the same decisions:
16
16
 
17
17
  - Where do API calls live?
18
18
  - How is auth state managed and persisted?
19
19
  - What's the folder structure when the app scales?
20
20
  - How are environment variables typed?
21
- - Where does validation logic go?
22
21
 
23
- This tool answers those questions upfront. You get a clean, feature-based structure with your chosen stack — ready to build on, not fight against.
22
+ This tool answers those questions upfront. You get a complete, typed, linted project with your chosen stack — ready to build on, not fight against.
24
23
 
25
24
  ---
26
25
 
27
- ## What It Generates
26
+ ## Quick Start
28
27
 
29
- The CLI walks you through a set of prompts and generates a complete project:
28
+ ```bash
29
+ # Interactive setup
30
+ npx @highbeek/create-rnstarterkit myApp
30
31
 
31
- ```
32
- src/
33
- app/ # App entry, shell, providers
34
- features/
35
- auth/ # Login, Register screens + auth flow (optional)
36
- screens/ # Additional screens
37
- navigation/ # React Navigation or Expo Router setup
38
- api/ # Axios/Fetch client + interceptors (optional)
39
- services/ # React Query client setup (optional)
40
- store/ # Redux / Zustand store (optional)
41
- config/ # Typed environment config
42
- hooks/ # Shared custom hooks
43
- utils/ # Shared utilities
44
- components/ # Shared UI components
45
- constants/ # App-wide constants
46
- types/ # TypeScript types and interfaces
47
- assets/
48
- images/
49
- fonts/
32
+ # Skip prompts with a preset
33
+ npx @highbeek/create-rnstarterkit myApp --preset fintech
34
+ npx @highbeek/create-rnstarterkit myApp --preset social
35
+ npx @highbeek/create-rnstarterkit myApp --preset indie
36
+ npx @highbeek/create-rnstarterkit myApp --preset minimal
50
37
  ```
51
38
 
52
39
  ---
53
40
 
54
- ## Installation
55
-
56
- ```bash
57
- npx @highbeek/create-rnstarterkit myApp
58
- ```
41
+ ## Presets
59
42
 
60
- Or install globally:
43
+ Presets bundle the most common stack combinations so you can skip all prompts:
61
44
 
62
- ```bash
63
- npm install -g @highbeek/create-rnstarterkit
64
- create-rnstarterkit myApp
65
- ```
45
+ | Preset | Platform | State | Auth | Data | Storage | Extras |
46
+ |---|---|---|---|---|---|---|
47
+ | `minimal` | Expo | None | No | None | None | Bare structure |
48
+ | `indie` | Either | Context API | Yes | React Query | AsyncStorage | Husky |
49
+ | `social` | Expo | Zustand | Yes | SWR | AsyncStorage | Sentry, i18n, CI |
50
+ | `fintech` | RN CLI | Redux Toolkit | Yes | React Query | MMKV | Sentry, i18n, Maestro, CI |
66
51
 
67
52
  ---
68
53
 
69
54
  ## Interactive Setup
70
55
 
71
- The CLI prompts you to configure your stack:
56
+ When run without a preset, the CLI walks you through your stack:
72
57
 
73
58
  ```
74
- ? Project name: myApp
75
- ? Platform: Expo / React Native CLI
76
- ? TypeScript: Yes / No
77
- ? Absolute imports (@/*): Yes / No
78
- ? State management: None / Context API / Redux Toolkit / Zustand
79
- ? Data fetching: None / React Query / SWR
80
- ? Form validation: None / Formik / React Hook Form + Yup
81
- ? Storage: AsyncStorage / MMKV / None
82
- ? Include auth scaffold: Yes / No
83
- ? Include API client: Yes / No (Fetch / Axios)
84
- ? Include CI setup: Yes / No
59
+ ? Project name:
60
+ ? Platform: Expo / React Native CLI
61
+ ? TypeScript: Yes / No
62
+ ? Absolute imports (@/*): Yes / No
63
+ ? State management: None / Context API / Redux Toolkit / Zustand
64
+ ? Data fetching: None / React Query / SWR
65
+ ? Validation: Formik / React Hook Form / Yup
66
+ ? Storage: AsyncStorage / MMKV / None
67
+ ? Auth scaffold: Yes / No
68
+ ? API client: Yes / NoFetch / Axios
69
+ ? Sentry: Yes / No
70
+ ? i18n (i18next): Yes / No
71
+ ? Maestro E2E flows: Yes / No
72
+ ? CI (GitHub Actions): Yes / No
73
+ ? Husky pre-commit hooks: Yes / No
85
74
  ```
86
75
 
87
76
  ---
88
77
 
89
- ## What's Included
90
-
91
- ### Platform Templates
92
-
93
- | Feature | Expo | React Native CLI |
94
- |---|---|---|
95
- | File-based routing | expo-router | — |
96
- | React Navigation | — | Native Stack v7 |
97
- | TypeScript | Default | Default |
98
- | Babel absolute imports | Optional | Optional |
99
- | ESLint + Prettier | Configured | Configured |
100
- | Jest | Configured | Configured |
101
- | Native iOS/Android | Managed | Full native project |
78
+ ## Generator Commands
102
79
 
103
- ### Auth Scaffold (Optional)
80
+ After scaffolding, use the `generate` subcommand to add code that matches your project's setup:
104
81
 
105
- Three implementations — pick one:
106
-
107
- **Context API** Recommended for most apps. Lightweight, no extra dependencies.
108
-
109
- **Redux Toolkit** If you're using Redux for global state. Comes with auth slice + persistence.
110
-
111
- **Zustand** — Minimal API, no boilerplate. Zustand store with AsyncStorage hydration.
112
-
113
- All three include:
114
- - Login + Register screens
115
- - Protected route stack
116
- - Token persistence via AsyncStorage
117
- - ScreenLayout wrapper component
82
+ ```bash
83
+ # Run from inside your generated project
84
+ npx @highbeek/create-rnstarterkit generate screen Dashboard
85
+ npx @highbeek/create-rnstarterkit generate component Avatar
86
+ npx @highbeek/create-rnstarterkit generate hook useDebounce
87
+ npx @highbeek/create-rnstarterkit generate slice cart
88
+ ```
118
89
 
119
- ### API Client (Optional)
90
+ Generators are context-aware — they read your project's config from `package.json` and produce files with the correct imports for your state manager, platform, and auth setup.
120
91
 
121
- **Fetch** Zero dependencies, typed wrapper with interceptors.
92
+ | Command | Output |
93
+ |---|---|
94
+ | `generate screen Name` | `src/screens/NameScreen.tsx` with correct state hook |
95
+ | `generate component Name` | `src/components/Name.tsx` with typed props + StyleSheet |
96
+ | `generate hook useName` | `src/hooks/useName.ts` with loading/error boilerplate |
97
+ | `generate slice name` | `src/store/nameSlice.ts` + auto-patches `store.ts` |
122
98
 
123
- **Axios** Full Axios instance with request/response interceptors, error normalisation, and typed response helpers.
99
+ > `generate slice` only works in Redux Toolkit projects. It automatically adds the reducer to your store.
124
100
 
125
- ### Environment Config
101
+ ---
126
102
 
127
- Typed environment variables with platform-aware setup:
103
+ ## What Gets Generated
128
104
 
129
- ```typescript
130
- // config/env.ts
131
- export const ENV = {
132
- API_BASE_URL: process.env.API_BASE_URL ?? "https://api.example.com",
133
- };
105
+ ```
106
+ <project>/
107
+ ├── src/
108
+ │ ├── api/ # API client + endpoints
109
+ │ ├── components/ # Shared UI components + ErrorBoundary
110
+ │ ├── config/ # Typed env config
111
+ │ ├── context/ # Context API providers (if selected)
112
+ │ ├── hooks/ # Shared custom hooks
113
+ │ ├── i18n/ # i18next config + locales (if selected)
114
+ │ ├── navigation/ # Navigation setup (RN CLI)
115
+ │ ├── providers/ # App-level providers
116
+ │ ├── screens/ # App screens
117
+ │ ├── services/ # Query clients, external services
118
+ │ ├── store/ # Redux / Zustand store (if selected)
119
+ │ ├── theme/ # Color tokens, spacing, typography
120
+ │ ├── types/ # Shared TypeScript types
121
+ │ └── utils/ # Shared utilities + Sentry (if selected)
122
+ ├── .env.example # Environment variable template
123
+ ├── .husky/ # Pre-commit hooks (if selected)
124
+ ├── .maestro/ # E2E flows (if selected)
125
+ ├── .vscode/ # Editor config + extension recommendations
126
+ └── .github/workflows/ # CI pipeline (if selected)
134
127
  ```
135
128
 
136
- Expo uses `EXPO_PUBLIC_*` variables. CLI uses `react-native-dotenv`.
137
-
138
- ### Data Fetching (Optional)
129
+ ---
139
130
 
140
- **React Query** — QueryClient pre-configured, ready to wrap your app.
131
+ ## Optional Modules
141
132
 
142
- **SWR** Installed and ready to use.
133
+ ### Auth Scaffold
143
134
 
144
- ### State Management (Optional)
135
+ Three implementations all include Login/Register screens, protected routes, token persistence, and a ScreenLayout wrapper:
145
136
 
146
- | Option | Package | Use When |
137
+ | Option | State | Best For |
147
138
  |---|---|---|
148
- | None | | App state is local |
149
- | Context API | Built-in React | Simple global state |
150
- | Redux Toolkit | @reduxjs/toolkit | Complex state, devtools |
151
- | Zustand | zustand | Minimal, fast, no boilerplate |
139
+ | Context API | Built-in React | Most apps |
140
+ | Redux Toolkit | `@reduxjs/toolkit` | Complex global state |
141
+ | Zustand | `zustand` | Minimal, no boilerplate |
152
142
 
153
- ### Validation (Optional)
143
+ ### API Client
154
144
 
155
- | Option | Packages |
145
+ | Option | Description |
156
146
  |---|---|
157
- | Formik | formik |
158
- | React Hook Form + Yup | react-hook-form + yup |
147
+ | Fetch | Zero deps — typed wrapper with request/response interceptors |
148
+ | Axios | Full Axios instance with error normalisation + typed helpers |
159
149
 
160
- ### Config / Tooling
150
+ ### Data Fetching
161
151
 
162
- - **ESLint** Extends `@react-native` config
163
- - **Prettier** — Single quotes, trailing commas, arrow parens
164
- - **Babel** Configured with optional dotenv + module-resolver plugins
165
- - **Jest** `react-native` preset with example test
152
+ | Option | Setup |
153
+ |---|---|
154
+ | React Query | QueryClient pre-configured with retry + stale time defaults |
155
+ | SWR | SWRConfig provider + typed `useSWRFetch` hook |
166
156
 
167
- ---
157
+ ### Storage
168
158
 
169
- ## Architecture Philosophy
159
+ | Option | Description |
160
+ |---|---|
161
+ | AsyncStorage | Default — async token persistence |
162
+ | MMKV | Synchronous, 10x faster, drop-in replacement |
170
163
 
171
- **Feature-based, not layer-based.**
164
+ ### Sentry
172
165
 
173
- Rather than grouping files by type (all screens together, all hooks together), related code lives together by feature. This scales better as the app grows.
166
+ Adds `@sentry/react-native`, initialises in the app entry point, and exports `captureException` + `addBreadcrumb` helpers. Replace `__YOUR_DSN__` in `src/utils/sentry.ts` with your project DSN.
174
167
 
175
- ```
176
- features/
177
- auth/
178
- screens/
179
- LoginScreen.tsx
180
- RegisterScreen.tsx
181
- hooks/
182
- useLogin.ts
183
- api/
184
- authApi.ts
185
- ```
168
+ ### i18n
186
169
 
187
- Shared code (components, utils, hooks used across features) lives in `shared/` or `components/` at the top level.
170
+ Adds `i18next` + `react-i18next` with:
171
+ - Language auto-detection via `react-native-localize`
172
+ - English + Spanish locale files as a starting point
173
+ - Typed `useAppTranslation` hook
188
174
 
189
- **Thin screens, fat services.**
175
+ ### Maestro E2E
190
176
 
191
- Screens handle UI and user interaction. Business logic, API calls, and state live in services/hooks. Screens don't call APIs directly.
177
+ Generates `.maestro/flows/` with welcome, login, and logout flows. Automatically adds a Maestro job to the CI workflow when both are selected.
192
178
 
193
- **Typed from the start.**
179
+ ### CI
194
180
 
195
- TypeScript is on by default. Environment variables are typed. API responses are typed. No `any` defaults.
181
+ GitHub Actions workflow with lint and test jobs on push/PR to `main` and `develop`.
196
182
 
197
183
  ---
198
184
 
199
- ## Roadmap
200
-
201
- **In Progress**
185
+ ## Tooling (Always Included)
202
186
 
203
- - [ ] MMKV storage integration (directory scaffolded, wiring in progress)
204
- - [ ] Theming system (color tokens, typography scale, theme provider)
205
- - [ ] Pre-commit hooks with Husky + lint-staged
206
-
207
- **Planned**
208
-
209
- - [ ] `@testing-library/react-native` setup
210
- - [ ] GitHub Actions CI workflow template
211
- - [ ] Dark mode support
212
- - [ ] Error boundary scaffold
213
- - [ ] i18n setup (react-i18next)
214
-
215
- **Not Planned (Intentionally)**
216
-
217
- - Custom UI component library — use your own or NativeBase, Tamagui, etc.
218
- - Analytics or tracking — too opinionated, too many options
219
- - Monorepo setup — out of scope for v1
187
+ | Tool | Config |
188
+ |---|---|
189
+ | TypeScript | `strict: true`, platform-native tsconfig |
190
+ | ESLint | `@react-native` ruleset, `--max-warnings 0` |
191
+ | Prettier | `format` script wired to `package.json` |
192
+ | Jest | RTL setup, `transformIgnorePatterns` for RN modules |
193
+ | VSCode | `extensions.json` + `settings.json` (format on save) |
194
+ | `.env.example` | Environment variable template + `.gitignore` entry |
195
+ | Theme | `colors.ts`, `spacing.ts`, `typography.ts` tokens |
196
+ | ErrorBoundary | Class component with reset, ready to wrap your app |
197
+ | Navigation types | `AuthStackParamList`, `MainTabParamList` (RN CLI + auth) |
220
198
 
221
199
  ---
222
200
 
223
- ## Status
201
+ ## Architecture
224
202
 
225
- Current version: `1.0.1-beta.3`
203
+ **Typed from the start.** TypeScript strict mode on by default. API responses, environment variables, and navigation params are all typed.
226
204
 
227
- This is a beta release. The core scaffolding (folder structure, auth, API client, state management) is working. Some optional modules (MMKV, theming) are scaffolded but not yet wired.
205
+ **Thin screens, fat hooks.** Screens handle UI. Business logic, API calls, and state live in hooks and services. Screens don't call APIs directly.
228
206
 
229
- Feedback and contributions welcome.
207
+ **Non-destructive generation.** `writeIfMissing` is used throughout — the generator never overwrites files you've already customised.
230
208
 
231
209
  ---
232
210
 
@@ -237,15 +215,24 @@ git clone https://github.com/highbeek/rnstarterkit
237
215
  cd rnstarterkit
238
216
  npm install
239
217
  npm run build
218
+
219
+ # Test locally
220
+ node dist/bin/create-rnstarterkit.js myTestApp
221
+ node dist/bin/create-rnstarterkit.js myTestApp --preset fintech
222
+
223
+ # Test generators (from inside a generated project)
224
+ node /path/to/rnstarterkit/dist/bin/create-rnstarterkit.js generate screen Dashboard
240
225
  ```
241
226
 
242
- Templates live in `src/templates/`. The generator logic is in `src/generators/appGenerator.ts`. Optional modules are in `src/templates/optional/`.
227
+ Templates live in `src/templates/`. Generator logic is in `src/generators/appGenerator.ts`. The `generate` subcommand is in `src/generators/codeGenerator.ts`.
243
228
 
244
- To test the CLI locally:
229
+ ---
245
230
 
246
- ```bash
247
- node dist/bin/create-rnstarterkit.js myTestApp
248
- ```
231
+ ## Status
232
+
233
+ Current version: `1.0.2-beta.13`
234
+
235
+ Beta release — core scaffolding, presets, and generators are working. Feedback and contributions welcome.
249
236
 
250
237
  ---
251
238
 
@@ -4,15 +4,90 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
7
8
  const inquirer_1 = __importDefault(require("inquirer"));
8
9
  const appGenerator_1 = require("../src/generators/appGenerator");
9
- async function main() {
10
- console.log("🚀 Welcome to RNStarterKit!");
10
+ const codeGenerator_1 = require("../src/generators/codeGenerator");
11
+ // ---------------------------------------------------------------------------
12
+ // Presets — opinionated bundles that skip the 12-question prompt
13
+ // ---------------------------------------------------------------------------
14
+ const PRESETS = {
15
+ minimal: {
16
+ typescript: true,
17
+ absoluteImports: false,
18
+ state: "None",
19
+ auth: false,
20
+ dataFetching: "None",
21
+ validation: [],
22
+ storage: "None",
23
+ apiClient: false,
24
+ ci: false,
25
+ husky: false,
26
+ sentry: false,
27
+ i18n: false,
28
+ maestro: false,
29
+ },
30
+ fintech: {
31
+ platform: "React Native CLI",
32
+ typescript: true,
33
+ absoluteImports: true,
34
+ state: "Redux Toolkit",
35
+ auth: true,
36
+ dataFetching: "React Query",
37
+ validation: [],
38
+ storage: "MMKV",
39
+ apiClient: true,
40
+ apiClientType: "Fetch",
41
+ ci: true,
42
+ husky: true,
43
+ sentry: true,
44
+ i18n: true,
45
+ maestro: true,
46
+ },
47
+ social: {
48
+ platform: "Expo",
49
+ typescript: true,
50
+ absoluteImports: true,
51
+ state: "Zustand",
52
+ auth: true,
53
+ dataFetching: "SWR",
54
+ validation: [],
55
+ storage: "AsyncStorage",
56
+ apiClient: true,
57
+ apiClientType: "Fetch",
58
+ ci: true,
59
+ husky: true,
60
+ sentry: true,
61
+ i18n: true,
62
+ maestro: false,
63
+ },
64
+ indie: {
65
+ typescript: true,
66
+ absoluteImports: true,
67
+ state: "Context API",
68
+ auth: true,
69
+ dataFetching: "React Query",
70
+ validation: [],
71
+ storage: "AsyncStorage",
72
+ apiClient: true,
73
+ apiClientType: "Fetch",
74
+ ci: false,
75
+ husky: true,
76
+ sentry: false,
77
+ i18n: false,
78
+ maestro: false,
79
+ },
80
+ };
81
+ // ---------------------------------------------------------------------------
82
+ // Interactive prompt
83
+ // ---------------------------------------------------------------------------
84
+ async function runInteractivePrompt(prefilledName, presetDefaults) {
11
85
  const answers = await inquirer_1.default.prompt([
12
86
  {
13
87
  type: "input",
14
88
  name: "projectName",
15
89
  message: "Project name:",
90
+ when: () => !prefilledName,
16
91
  validate: (input) => /^[A-Za-z0-9]+$/.test(input)
17
92
  ? true
18
93
  : "Project name must be alphanumeric",
@@ -22,18 +97,21 @@ async function main() {
22
97
  name: "platform",
23
98
  message: "Choose platform",
24
99
  choices: ["Expo", "React Native CLI"],
100
+ when: () => !presetDefaults?.platform,
25
101
  },
26
102
  {
27
103
  type: "confirm",
28
104
  name: "typescript",
29
105
  message: "Use TypeScript?",
30
106
  default: true,
107
+ when: () => presetDefaults?.typescript === undefined,
31
108
  },
32
109
  {
33
110
  type: "confirm",
34
111
  name: "absoluteImports",
35
112
  message: "Use absolute import alias (@/*)?",
36
113
  default: true,
114
+ when: () => presetDefaults?.absoluteImports === undefined,
37
115
  },
38
116
  {
39
117
  type: "rawlist",
@@ -41,6 +119,7 @@ async function main() {
41
119
  message: "State management?",
42
120
  choices: ["None", "Context API", "Redux Toolkit", "Zustand"],
43
121
  default: "Context API",
122
+ when: () => !presetDefaults?.state,
44
123
  },
45
124
  {
46
125
  type: "rawlist",
@@ -48,6 +127,7 @@ async function main() {
48
127
  message: "Data fetching library?",
49
128
  choices: ["None", "React Query", "SWR"],
50
129
  default: "None",
130
+ when: () => !presetDefaults?.dataFetching,
51
131
  },
52
132
  {
53
133
  type: "checkbox",
@@ -55,6 +135,7 @@ async function main() {
55
135
  message: "Validation libraries?",
56
136
  choices: ["Formik", "React Hook Form", "Yup"],
57
137
  default: [],
138
+ when: () => !presetDefaults?.validation?.length,
58
139
  validate: (selected) => {
59
140
  if (selected.includes("Formik") && !selected.includes("Yup")) {
60
141
  return "Formik requires Yup in this starter. Select Yup as well.";
@@ -68,18 +149,21 @@ async function main() {
68
149
  message: "Storage method?",
69
150
  choices: ["AsyncStorage", "MMKV", "None"],
70
151
  default: "AsyncStorage",
152
+ when: () => !presetDefaults?.storage,
71
153
  },
72
154
  {
73
155
  type: "confirm",
74
156
  name: "auth",
75
157
  message: "Include auth scaffold?",
76
158
  default: false,
159
+ when: () => presetDefaults?.auth === undefined,
77
160
  },
78
161
  {
79
162
  type: "confirm",
80
163
  name: "apiClient",
81
164
  message: "Include API client scaffold?",
82
165
  default: true,
166
+ when: () => presetDefaults?.apiClient === undefined,
83
167
  },
84
168
  {
85
169
  type: "rawlist",
@@ -87,25 +171,119 @@ async function main() {
87
171
  message: "API client transport?",
88
172
  choices: ["Fetch", "Axios"],
89
173
  default: "Fetch",
90
- when: (answers) => answers.apiClient,
174
+ when: (a) => presetDefaults?.apiClientType === undefined && a.apiClient,
175
+ },
176
+ {
177
+ type: "confirm",
178
+ name: "sentry",
179
+ message: "Include Sentry crash reporting?",
180
+ default: false,
181
+ when: () => presetDefaults?.sentry === undefined,
182
+ },
183
+ {
184
+ type: "confirm",
185
+ name: "i18n",
186
+ message: "Include i18n (i18next + react-i18next)?",
187
+ default: false,
188
+ when: () => presetDefaults?.i18n === undefined,
189
+ },
190
+ {
191
+ type: "confirm",
192
+ name: "maestro",
193
+ message: "Include Maestro E2E test flows?",
194
+ default: false,
195
+ when: () => presetDefaults?.maestro === undefined,
91
196
  },
92
197
  {
93
198
  type: "confirm",
94
199
  name: "ci",
95
- message: "Include CI setup?",
200
+ message: "Include CI setup (GitHub Actions)?",
96
201
  default: false,
202
+ when: () => presetDefaults?.ci === undefined,
97
203
  },
98
204
  {
99
205
  type: "confirm",
100
206
  name: "husky",
101
207
  message: "Set up Husky pre-commit hooks (lint-staged)?",
102
208
  default: true,
209
+ when: () => presetDefaults?.husky === undefined,
103
210
  },
104
211
  ]);
105
- await (0, appGenerator_1.generateApp)(answers);
212
+ return {
213
+ projectName: prefilledName ?? answers.projectName,
214
+ platform: answers.platform ?? presetDefaults?.platform ?? "Expo",
215
+ typescript: answers.typescript ?? presetDefaults?.typescript ?? true,
216
+ absoluteImports: answers.absoluteImports ?? presetDefaults?.absoluteImports ?? true,
217
+ state: answers.state ?? presetDefaults?.state ?? "None",
218
+ auth: answers.auth ?? presetDefaults?.auth ?? false,
219
+ dataFetching: answers.dataFetching ?? presetDefaults?.dataFetching ?? "None",
220
+ validation: answers.validation ?? presetDefaults?.validation ?? [],
221
+ storage: answers.storage ?? presetDefaults?.storage ?? "AsyncStorage",
222
+ apiClient: answers.apiClient ?? presetDefaults?.apiClient ?? false,
223
+ apiClientType: answers.apiClientType ?? presetDefaults?.apiClientType,
224
+ sentry: answers.sentry ?? presetDefaults?.sentry ?? false,
225
+ i18n: answers.i18n ?? presetDefaults?.i18n ?? false,
226
+ maestro: answers.maestro ?? presetDefaults?.maestro ?? false,
227
+ ci: answers.ci ?? presetDefaults?.ci ?? false,
228
+ husky: answers.husky ?? presetDefaults?.husky ?? true,
229
+ };
106
230
  }
107
- main().catch((error) => {
108
- console.error("❌ Failed to create project.");
231
+ // ---------------------------------------------------------------------------
232
+ // CLI wiring
233
+ // ---------------------------------------------------------------------------
234
+ const program = new commander_1.Command();
235
+ program
236
+ .name("create-rnstarterkit")
237
+ .description("Scaffold a production-ready React Native app")
238
+ .version("1.0.2-beta.12")
239
+ .argument("[projectName]", "Name of the project (alphanumeric)")
240
+ .option("--preset <name>", "Skip prompts with a preset: minimal | fintech | social | indie")
241
+ .action(async (projectName, cmdOptions) => {
242
+ console.log("🚀 Welcome to RNStarterKit!");
243
+ const presetKey = cmdOptions.preset;
244
+ if (presetKey && !(presetKey in PRESETS)) {
245
+ console.error(`❌ Unknown preset "${presetKey}". Available: ${Object.keys(PRESETS).join(", ")}`);
246
+ process.exit(1);
247
+ }
248
+ const presetDefaults = presetKey ? PRESETS[presetKey] : undefined;
249
+ // Preset + name supplied → fully non-interactive
250
+ if (presetDefaults && projectName) {
251
+ const options = {
252
+ projectName,
253
+ platform: presetDefaults.platform ?? "Expo",
254
+ typescript: presetDefaults.typescript ?? true,
255
+ absoluteImports: presetDefaults.absoluteImports ?? true,
256
+ state: presetDefaults.state ?? "None",
257
+ auth: presetDefaults.auth ?? false,
258
+ dataFetching: presetDefaults.dataFetching ?? "None",
259
+ validation: presetDefaults.validation ?? [],
260
+ storage: presetDefaults.storage ?? "AsyncStorage",
261
+ apiClient: presetDefaults.apiClient ?? false,
262
+ apiClientType: presetDefaults.apiClientType,
263
+ sentry: presetDefaults.sentry ?? false,
264
+ i18n: presetDefaults.i18n ?? false,
265
+ maestro: presetDefaults.maestro ?? false,
266
+ ci: presetDefaults.ci ?? false,
267
+ husky: presetDefaults.husky ?? true,
268
+ };
269
+ console.log(`⚡ Using preset: ${presetKey}`);
270
+ await (0, appGenerator_1.generateApp)(options);
271
+ }
272
+ else {
273
+ const options = await runInteractivePrompt(projectName, presetDefaults);
274
+ await (0, appGenerator_1.generateApp)(options);
275
+ }
276
+ });
277
+ // generate subcommand
278
+ program
279
+ .command("generate <type> <name>")
280
+ .description("Generate code inside an existing rnstarterkit project\n" +
281
+ " Types: screen | component | hook | slice")
282
+ .action(async (type, name) => {
283
+ await (0, codeGenerator_1.generateCode)(type, name);
284
+ });
285
+ program.parseAsync(process.argv).catch((error) => {
286
+ console.error("❌ Failed.");
109
287
  console.error(error);
110
288
  process.exit(1);
111
289
  });