rnsup 1.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.
- package/LICENSE +7 -0
- package/README.md +331 -0
- package/bin/rnsup.js +2 -0
- package/dist/commands/generateComponent.js +70 -0
- package/dist/commands/generateScreen.js +84 -0
- package/dist/commands/setup.js +145 -0
- package/dist/index.js +34 -0
- package/dist/templates/component.js +24 -0
- package/dist/templates/screen.js +26 -0
- package/dist/utils/alias.js +62 -0
- package/dist/utils/aliasManager.js +57 -0
- package/dist/utils/config.js +20 -0
- package/dist/utils/createApiClient.js +48 -0
- package/dist/utils/createDocs.js +65 -0
- package/dist/utils/createResponsive.js +50 -0
- package/dist/utils/createTypes.js +19 -0
- package/dist/utils/detectProject.js +21 -0
- package/dist/utils/file.js +25 -0
- package/dist/utils/handleCancel.js +14 -0
- package/dist/utils/history.js +24 -0
- package/dist/utils/install.js +29 -0
- package/dist/utils/lockfile.js +25 -0
- package/dist/utils/packageManager.js +23 -0
- package/dist/utils/parseComponentName.js +29 -0
- package/dist/utils/parseName.js +44 -0
- package/dist/utils/patchIndex.js +19 -0
- package/dist/utils/selectPrompt.js +34 -0
- package/package.json +67 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# RNSUP — React Native Support CLI
|
|
2
|
+
|
|
3
|
+
**RNSUP** is a developer productivity CLI that converts a fresh React Native CLI project into a production-ready architecture.
|
|
4
|
+
|
|
5
|
+
Instead of spending 2–3 days configuring navigation, alias paths, reanimated, gesture handler, axios setup and folder structure, you can do everything with **one command**.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why RNSUP?
|
|
10
|
+
|
|
11
|
+
Starting a React Native CLI project usually requires:
|
|
12
|
+
|
|
13
|
+
* Installing React Navigation dependencies
|
|
14
|
+
* Configuring Reanimated
|
|
15
|
+
* Adding Gesture Handler import
|
|
16
|
+
* Setting up TypeScript aliases
|
|
17
|
+
* Creating folder structure
|
|
18
|
+
* Writing axios interceptors
|
|
19
|
+
* Adding responsive utilities
|
|
20
|
+
* Supporting image imports in TypeScript
|
|
21
|
+
|
|
22
|
+
Most developers repeat this setup for every project.
|
|
23
|
+
|
|
24
|
+
**RNSUP automates all of it.**
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## What RNSUP Does
|
|
29
|
+
|
|
30
|
+
After running setup, your project automatically gets:
|
|
31
|
+
|
|
32
|
+
### Configuration
|
|
33
|
+
|
|
34
|
+
* React Navigation dependencies installed
|
|
35
|
+
* Reanimated + Worklets configured
|
|
36
|
+
* Gesture Handler patched
|
|
37
|
+
* Babel alias configuration
|
|
38
|
+
* TypeScript path aliases
|
|
39
|
+
* Lockfile conflict handled (npm/yarn)
|
|
40
|
+
|
|
41
|
+
### Architecture
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
src/
|
|
45
|
+
components/
|
|
46
|
+
screens/
|
|
47
|
+
services/
|
|
48
|
+
utils/
|
|
49
|
+
hooks/
|
|
50
|
+
store/
|
|
51
|
+
theme/
|
|
52
|
+
assets/
|
|
53
|
+
types/
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Utilities Added
|
|
57
|
+
|
|
58
|
+
* Axios API client with interceptors
|
|
59
|
+
* Responsive screen helpers
|
|
60
|
+
* Image import TypeScript support
|
|
61
|
+
* Clean folder structure
|
|
62
|
+
|
|
63
|
+
### Developer Experience
|
|
64
|
+
|
|
65
|
+
* Auto import aliases (`@components`, `@services`, etc.)
|
|
66
|
+
* Code generators (screens & components)
|
|
67
|
+
* History tracking
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Installation
|
|
72
|
+
|
|
73
|
+
You DO NOT install RNSUP globally.
|
|
74
|
+
|
|
75
|
+
Use directly via npx:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx rnsup setup
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Quick Start
|
|
84
|
+
|
|
85
|
+
### 1) Create React Native Project
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx react-native@latest init MyApp
|
|
89
|
+
cd MyApp
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2) Run RNSUP
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx rnsup setup
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Follow the prompts.
|
|
99
|
+
|
|
100
|
+
After setup:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npx react-native start --reset-cache
|
|
104
|
+
npx react-native run-android
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Your project is ready.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Commands
|
|
112
|
+
|
|
113
|
+
### Setup Project
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
npx rnsup setup
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### Generate Screen
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
rnsup g s Login
|
|
125
|
+
rnsup g s auth/Login
|
|
126
|
+
rnsup g s features/auth/Login
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Examples created:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
src/screens/LoginScreen.tsx
|
|
133
|
+
src/auth/LoginScreen.tsx
|
|
134
|
+
src/features/auth/LoginScreen.tsx
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Generate Component
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
rnsup g c Button
|
|
143
|
+
rnsup g c ui/forms/Input
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Created:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
src/components/Button.tsx
|
|
150
|
+
src/components/ui/forms/Input.tsx
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Auto Alias Support
|
|
156
|
+
|
|
157
|
+
You can import without relative paths.
|
|
158
|
+
|
|
159
|
+
Instead of:
|
|
160
|
+
|
|
161
|
+
```ts
|
|
162
|
+
import Button from '../../../components/Button';
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Use:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import Button from '@components/Button';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Aliases automatically configured:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
@components
|
|
175
|
+
@services
|
|
176
|
+
@utils
|
|
177
|
+
@hooks
|
|
178
|
+
@store
|
|
179
|
+
@theme
|
|
180
|
+
@assets
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
New folders inside `src` automatically get alias support.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Axios Usage
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import api from '@services/api/client';
|
|
191
|
+
|
|
192
|
+
const users = await api.get('/users');
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Interceptors already configured.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Responsive Utility
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { widthPercentageToDP as wp } from '@utils/responsive-screen';
|
|
203
|
+
|
|
204
|
+
<View style={{ width: wp(80) }} />
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Image Import Support
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import logo from '@assets/logo.png';
|
|
213
|
+
|
|
214
|
+
<Image source={logo} />
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
No TypeScript error.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Why It Is Useful
|
|
222
|
+
|
|
223
|
+
RNSUP removes repetitive setup work and enforces a consistent architecture across projects and teams.
|
|
224
|
+
|
|
225
|
+
Benefits:
|
|
226
|
+
|
|
227
|
+
* Saves 3–6 hours per project
|
|
228
|
+
* Prevents configuration mistakes
|
|
229
|
+
* Standardizes project structure
|
|
230
|
+
* Faster onboarding for new developers
|
|
231
|
+
* Clean import paths
|
|
232
|
+
* Production-ready base
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Best Practices
|
|
237
|
+
|
|
238
|
+
Recommended workflow:
|
|
239
|
+
|
|
240
|
+
1. Create project
|
|
241
|
+
2. Run `rnsup setup`
|
|
242
|
+
3. Only create screens/components using `rnsup g`
|
|
243
|
+
4. Avoid manual folder creation inside `src`
|
|
244
|
+
|
|
245
|
+
This ensures aliases and exports always remain correct.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Publishing to NPM
|
|
250
|
+
|
|
251
|
+
### 1) Login
|
|
252
|
+
|
|
253
|
+
Create an account at:
|
|
254
|
+
https://www.npmjs.com
|
|
255
|
+
|
|
256
|
+
Then:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npm login
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### 2) Prepare package.json
|
|
265
|
+
|
|
266
|
+
Make sure:
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{
|
|
270
|
+
"name": "rnsup",
|
|
271
|
+
"version": "1.0.0",
|
|
272
|
+
"bin": {
|
|
273
|
+
"rnsup": "bin/rnsup.js"
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### 3) Build project
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
npm run build
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
### 4) Publish
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
npm publish --access public
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Your package is now live.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Using After Publish
|
|
299
|
+
|
|
300
|
+
Anyone can run:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
npx rnsup setup
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
No installation required.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Updating Package
|
|
311
|
+
|
|
312
|
+
After changes:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
npm version patch
|
|
316
|
+
npm publish
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Contribution
|
|
322
|
+
|
|
323
|
+
Pull requests are welcome.
|
|
324
|
+
|
|
325
|
+
If you find a bug or want a feature, open an issue.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
MIT License
|
package/bin/rnsup.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateComponent = generateComponent;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const component_1 = require("../templates/component");
|
|
12
|
+
const parseComponentName_1 = require("../utils/parseComponentName");
|
|
13
|
+
const aliasManager_1 = require("../utils/aliasManager");
|
|
14
|
+
const history_1 = require("../utils/history");
|
|
15
|
+
async function generateComponent(input) {
|
|
16
|
+
try {
|
|
17
|
+
const { componentName, fullDir, relativeDir } = (0, parseComponentName_1.parseComponentName)(input);
|
|
18
|
+
const filePath = path_1.default.join(fullDir, `${componentName}.tsx`);
|
|
19
|
+
console.log('\nComponent details:');
|
|
20
|
+
console.log('Name:', componentName);
|
|
21
|
+
console.log('Directory:', relativeDir);
|
|
22
|
+
// overwrite check
|
|
23
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
24
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'confirm',
|
|
27
|
+
name: 'overwrite',
|
|
28
|
+
message: `${componentName} already exists. Overwrite?`,
|
|
29
|
+
default: false
|
|
30
|
+
}
|
|
31
|
+
]);
|
|
32
|
+
if (!overwrite) {
|
|
33
|
+
console.log(chalk_1.default.yellow('Cancelled.'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'confirm',
|
|
40
|
+
name: 'confirm',
|
|
41
|
+
message: `Create ${componentName} in ${relativeDir}?`,
|
|
42
|
+
default: true
|
|
43
|
+
}
|
|
44
|
+
]);
|
|
45
|
+
if (!confirm)
|
|
46
|
+
return;
|
|
47
|
+
// create directory
|
|
48
|
+
await fs_extra_1.default.ensureDir(fullDir);
|
|
49
|
+
// ensure alias (for nested components like ui/forms)
|
|
50
|
+
await (0, aliasManager_1.registerAlias)(relativeDir);
|
|
51
|
+
// write component
|
|
52
|
+
await fs_extra_1.default.writeFile(filePath, (0, component_1.componentTemplate)(componentName));
|
|
53
|
+
// create index export
|
|
54
|
+
const indexFile = path_1.default.join(fullDir, 'index.ts');
|
|
55
|
+
const exportLine = `export { default as ${componentName} } from './${componentName}';\n`;
|
|
56
|
+
if (await fs_extra_1.default.pathExists(indexFile)) {
|
|
57
|
+
const existing = await fs_extra_1.default.readFile(indexFile, 'utf8');
|
|
58
|
+
if (!existing.includes(componentName))
|
|
59
|
+
await fs_extra_1.default.appendFile(indexFile, exportLine);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
await fs_extra_1.default.writeFile(indexFile, exportLine);
|
|
63
|
+
}
|
|
64
|
+
await (0, history_1.addHistory)(`Generated component ${componentName}`);
|
|
65
|
+
console.log(chalk_1.default.green(`\n${componentName} created successfully.`));
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error(err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateScreen = generateScreen;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const parseName_1 = require("../utils/parseName");
|
|
12
|
+
const screen_1 = require("../templates/screen");
|
|
13
|
+
const history_1 = require("../utils/history");
|
|
14
|
+
const aliasManager_1 = require("../utils/aliasManager");
|
|
15
|
+
async function generateScreen(input) {
|
|
16
|
+
try {
|
|
17
|
+
const { screenName, fullDir, relativeDir } = await (0, parseName_1.parseScreenName)(input);
|
|
18
|
+
const filePath = path_1.default.join(fullDir, `${screenName}.tsx`);
|
|
19
|
+
console.log('\nScreen details:');
|
|
20
|
+
console.log('Name:', screenName);
|
|
21
|
+
console.log('Directory:', relativeDir);
|
|
22
|
+
// confirm directory creation
|
|
23
|
+
if (!(await fs_extra_1.default.pathExists(fullDir))) {
|
|
24
|
+
const { createDir } = await inquirer_1.default.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'confirm',
|
|
27
|
+
name: 'createDir',
|
|
28
|
+
message: `Directory ${relativeDir} does not exist. Create it?`,
|
|
29
|
+
default: true
|
|
30
|
+
}
|
|
31
|
+
]);
|
|
32
|
+
if (!createDir) {
|
|
33
|
+
console.log(chalk_1.default.yellow('Cancelled.'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// overwrite check
|
|
38
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
39
|
+
const { overwrite } = await inquirer_1.default.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'confirm',
|
|
42
|
+
name: 'overwrite',
|
|
43
|
+
message: `${screenName} already exists. Overwrite?`,
|
|
44
|
+
default: false
|
|
45
|
+
}
|
|
46
|
+
]);
|
|
47
|
+
if (!overwrite) {
|
|
48
|
+
console.log(chalk_1.default.yellow('Operation cancelled.'));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const { confirm } = await inquirer_1.default.prompt([
|
|
53
|
+
{
|
|
54
|
+
type: 'confirm',
|
|
55
|
+
name: 'confirm',
|
|
56
|
+
message: `Create ${screenName} in ${relativeDir}?`,
|
|
57
|
+
default: true
|
|
58
|
+
}
|
|
59
|
+
]);
|
|
60
|
+
if (!confirm) {
|
|
61
|
+
console.log(chalk_1.default.yellow('Cancelled.'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await fs_extra_1.default.ensureDir(fullDir);
|
|
65
|
+
await (0, aliasManager_1.registerAlias)(relativeDir);
|
|
66
|
+
await fs_extra_1.default.writeFile(filePath, (0, screen_1.screenTemplate)(screenName));
|
|
67
|
+
// create index export
|
|
68
|
+
const indexFile = path_1.default.join(fullDir, 'index.ts');
|
|
69
|
+
const exportLine = `export { default as ${screenName} } from './${screenName}';\n`;
|
|
70
|
+
if (await fs_extra_1.default.pathExists(indexFile)) {
|
|
71
|
+
const existing = await fs_extra_1.default.readFile(indexFile, 'utf8');
|
|
72
|
+
if (!existing.includes(screenName))
|
|
73
|
+
await fs_extra_1.default.appendFile(indexFile, exportLine);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
await fs_extra_1.default.writeFile(indexFile, exportLine);
|
|
77
|
+
}
|
|
78
|
+
await (0, history_1.addHistory)(`Generated screen ${screenName}`);
|
|
79
|
+
console.log(chalk_1.default.green(`\n${screenName} created successfully.`));
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.error(err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runSetup = runSetup;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const ora_1 = __importDefault(require("ora"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const selectPrompt_1 = require("../utils/selectPrompt");
|
|
11
|
+
const detectProject_1 = require("../utils/detectProject");
|
|
12
|
+
const config_1 = require("../utils/config");
|
|
13
|
+
const file_1 = require("../utils/file");
|
|
14
|
+
const history_1 = require("../utils/history");
|
|
15
|
+
const install_1 = require("../utils/install");
|
|
16
|
+
const alias_1 = require("../utils/alias");
|
|
17
|
+
const patchIndex_1 = require("../utils/patchIndex");
|
|
18
|
+
const lockfile_1 = require("../utils/lockfile");
|
|
19
|
+
const packageManager_1 = require("../utils/packageManager");
|
|
20
|
+
const createTypes_1 = require("../utils/createTypes");
|
|
21
|
+
const createResponsive_1 = require("../utils/createResponsive");
|
|
22
|
+
const createApiClient_1 = require("../utils/createApiClient");
|
|
23
|
+
const createDocs_1 = require("../utils/createDocs");
|
|
24
|
+
const handleCancel_1 = require("../utils/handleCancel");
|
|
25
|
+
process.on('SIGINT', () => {
|
|
26
|
+
console.log('\nCancelled by user.\n');
|
|
27
|
+
process.exit(0);
|
|
28
|
+
});
|
|
29
|
+
async function runSetup() {
|
|
30
|
+
try {
|
|
31
|
+
console.log(chalk_1.default.cyan('\nRNSUP Setup\n'));
|
|
32
|
+
/* ---------- 1. Verify RN project ---------- */
|
|
33
|
+
if (!(0, detectProject_1.isReactNativeProject)()) {
|
|
34
|
+
console.log(chalk_1.default.red('Not a React Native CLI project'));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
/* ---------- 2. Ask package manager ---------- */
|
|
38
|
+
const manager = await (0, selectPrompt_1.selectOption)('Which package manager do you want to use?', ['npm', 'yarn', 'pnpm']);
|
|
39
|
+
/* ---------- 3. Validate manager installed ---------- */
|
|
40
|
+
if (!(0, packageManager_1.isInstalled)(manager)) {
|
|
41
|
+
console.log('\nSelected package manager is not installed on your system.\n');
|
|
42
|
+
if (manager === 'yarn') {
|
|
43
|
+
console.log('Install yarn using:');
|
|
44
|
+
console.log('npm install -g yarn');
|
|
45
|
+
}
|
|
46
|
+
if (manager === 'pnpm') {
|
|
47
|
+
console.log('Install pnpm using:');
|
|
48
|
+
console.log('npm install -g pnpm');
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
/* ---------- 4. Fix lockfile conflict ---------- */
|
|
53
|
+
await (0, lockfile_1.fixLockFile)(manager);
|
|
54
|
+
/* ---------- 5. Ask navigation ---------- */
|
|
55
|
+
const { navigation } = await inquirer_1.default.prompt([
|
|
56
|
+
{
|
|
57
|
+
type: 'checkbox',
|
|
58
|
+
name: 'navigation',
|
|
59
|
+
message: 'Select navigation types',
|
|
60
|
+
choices: [
|
|
61
|
+
{ name: 'Stack', value: 'stack' },
|
|
62
|
+
{ name: 'Bottom Tabs', value: 'tabs' },
|
|
63
|
+
{ name: 'Drawer', value: 'drawer' }
|
|
64
|
+
],
|
|
65
|
+
validate: (ans) => ans.length === 0 ? 'Select at least one navigation type' : true
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
/* ---------- 6. Optional libraries ---------- */
|
|
69
|
+
const { svg, lucide } = await inquirer_1.default.prompt([
|
|
70
|
+
{
|
|
71
|
+
type: 'confirm',
|
|
72
|
+
name: 'svg',
|
|
73
|
+
message: 'Install react-native-svg?',
|
|
74
|
+
default: true
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: 'confirm',
|
|
78
|
+
name: 'lucide',
|
|
79
|
+
message: 'Install lucide-react-native?',
|
|
80
|
+
default: true
|
|
81
|
+
}
|
|
82
|
+
]);
|
|
83
|
+
/* ---------- 7. Start setup ---------- */
|
|
84
|
+
const spinner = (0, ora_1.default)('Preparing project...').start();
|
|
85
|
+
// create folders
|
|
86
|
+
await (0, file_1.createBaseFolders)();
|
|
87
|
+
/* ---------- 8. Collect dependencies ---------- */
|
|
88
|
+
const dependencies = [
|
|
89
|
+
'@react-navigation/native',
|
|
90
|
+
'react-native-screens',
|
|
91
|
+
'react-native-advanced-checkbox',
|
|
92
|
+
'react-native-gesture-handler',
|
|
93
|
+
'react-native-reanimated',
|
|
94
|
+
'react-native-worklets',
|
|
95
|
+
'react-native-vector-icons',
|
|
96
|
+
'zustand',
|
|
97
|
+
'axios',
|
|
98
|
+
'@tanstack/react-query',
|
|
99
|
+
'react-native-mmkv'
|
|
100
|
+
];
|
|
101
|
+
// navigation specific
|
|
102
|
+
if (navigation.includes('stack'))
|
|
103
|
+
dependencies.push('@react-navigation/native-stack');
|
|
104
|
+
if (navigation.includes('tabs'))
|
|
105
|
+
dependencies.push('@react-navigation/bottom-tabs');
|
|
106
|
+
if (navigation.includes('drawer'))
|
|
107
|
+
dependencies.push('@react-navigation/drawer');
|
|
108
|
+
// optional libs
|
|
109
|
+
if (svg)
|
|
110
|
+
dependencies.push('react-native-svg');
|
|
111
|
+
if (lucide)
|
|
112
|
+
dependencies.push('lucide-react-native');
|
|
113
|
+
const devDependencies = ['babel-plugin-module-resolver'];
|
|
114
|
+
/* ---------- 9. Install ---------- */
|
|
115
|
+
spinner.text = 'Installing dependencies...';
|
|
116
|
+
await (0, install_1.installPackages)(manager, dependencies);
|
|
117
|
+
await (0, install_1.installPackages)(manager, devDependencies, true);
|
|
118
|
+
/* ---------- 10. Configure project ---------- */
|
|
119
|
+
spinner.text = 'Configuring babel, alias and gesture handler...';
|
|
120
|
+
await (0, alias_1.setupTsAlias)();
|
|
121
|
+
await (0, alias_1.setupBabelAlias)();
|
|
122
|
+
await (0, patchIndex_1.patchIndexFile)();
|
|
123
|
+
await (0, createTypes_1.createTypes)();
|
|
124
|
+
await (0, createResponsive_1.createResponsiveFile)();
|
|
125
|
+
await (0, createApiClient_1.createApiClient)();
|
|
126
|
+
await (0, createDocs_1.createDocs)();
|
|
127
|
+
/* ---------- 11. Save config ---------- */
|
|
128
|
+
await (0, config_1.saveConfig)({
|
|
129
|
+
packageManager: manager,
|
|
130
|
+
navigation,
|
|
131
|
+
svg,
|
|
132
|
+
lucide
|
|
133
|
+
});
|
|
134
|
+
await (0, history_1.addHistory)('Project setup completed');
|
|
135
|
+
/* ---------- 12. Finish ---------- */
|
|
136
|
+
spinner.succeed('RNSUP setup completed successfully');
|
|
137
|
+
console.log(chalk_1.default.green('\nImportant steps:'));
|
|
138
|
+
console.log('1. cd ios && pod install (only macOS)');
|
|
139
|
+
console.log('2. npx react-native start --reset-cache');
|
|
140
|
+
console.log('3. npx react-native run-android');
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
(0, handleCancel_1.handleCancel)(err);
|
|
144
|
+
}
|
|
145
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const commander_1 = require("commander");
|
|
4
|
+
const setup_1 = require("./commands/setup");
|
|
5
|
+
const generateScreen_1 = require("./commands/generateScreen");
|
|
6
|
+
const generateComponent_1 = require("./commands/generateComponent");
|
|
7
|
+
const program = new commander_1.Command();
|
|
8
|
+
program
|
|
9
|
+
.name('rnsup')
|
|
10
|
+
.description('React Native Support CLI')
|
|
11
|
+
.version('1.0.0');
|
|
12
|
+
/* ---------- Setup ---------- */
|
|
13
|
+
program
|
|
14
|
+
.command('setup')
|
|
15
|
+
.description('Configure React Native project')
|
|
16
|
+
.action(setup_1.runSetup);
|
|
17
|
+
/* ---------- Generator Root ---------- */
|
|
18
|
+
const generate = new commander_1.Command('generate')
|
|
19
|
+
.alias('g')
|
|
20
|
+
.description('Generate files');
|
|
21
|
+
/* ---------- Screen ---------- */
|
|
22
|
+
generate
|
|
23
|
+
.command('screen <name>')
|
|
24
|
+
.alias('s')
|
|
25
|
+
.description('Generate a screen')
|
|
26
|
+
.action(generateScreen_1.generateScreen);
|
|
27
|
+
generate
|
|
28
|
+
.command('component <name>')
|
|
29
|
+
.alias('c')
|
|
30
|
+
.description('Generate a component')
|
|
31
|
+
.action(generateComponent_1.generateComponent);
|
|
32
|
+
/* attach to main program */
|
|
33
|
+
program.addCommand(generate);
|
|
34
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.componentTemplate = componentTemplate;
|
|
4
|
+
function componentTemplate(name) {
|
|
5
|
+
return `import React from 'react';
|
|
6
|
+
import { View, Text, StyleSheet } from 'react-native';
|
|
7
|
+
|
|
8
|
+
interface Props {}
|
|
9
|
+
|
|
10
|
+
const ${name}: React.FC<Props> = () => {
|
|
11
|
+
return (
|
|
12
|
+
<View style={styles.container}>
|
|
13
|
+
<Text>${name}</Text>
|
|
14
|
+
</View>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default ${name};
|
|
19
|
+
|
|
20
|
+
const styles = StyleSheet.create({
|
|
21
|
+
container: {},
|
|
22
|
+
});
|
|
23
|
+
`;
|
|
24
|
+
}
|