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 ADDED
@@ -0,0 +1,7 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 getsettalk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction...
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,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/index.js');
@@ -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
+ }