rnsup 1.0.2 → 1.0.3

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.
@@ -35,7 +35,7 @@ async function runSetup() {
35
35
  process.exit(1);
36
36
  }
37
37
  /* ---------- 2. Ask package manager ---------- */
38
- const manager = await (0, selectPrompt_1.selectOption)('Which package manager do you want to use?', ['npm', 'yarn', 'pnpm']);
38
+ const manager = await (0, selectPrompt_1.selectOption)('Which package manager do you want to use?', ['npm', 'yarn', 'pnpm'], 'yarn');
39
39
  /* ---------- 3. Validate manager installed ---------- */
40
40
  if (!(0, packageManager_1.isInstalled)(manager)) {
41
41
  console.log('\nSelected package manager is not installed on your system.\n');
@@ -0,0 +1,91 @@
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.viewStructure = viewStructure;
7
+ const path_1 = __importDefault(require("path"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const treeGenerator_1 = require("../utils/treeGenerator");
11
+ const handleCancel_1 = require("../utils/handleCancel");
12
+ async function viewStructure(options) {
13
+ try {
14
+ // Handle Ctrl+C gracefully
15
+ process.on('SIGINT', () => {
16
+ console.log(chalk_1.default.yellow('\n\nCancelled.'));
17
+ process.exit(0);
18
+ });
19
+ // Parse flags
20
+ const pretty = options.pretty || options.p || false;
21
+ const showTime = options.time || false;
22
+ // Show hints if first time or no input
23
+ if (!options.parent?.args?.[1]) {
24
+ console.log('\n' + chalk_1.default.cyan.bold('💡 Usage Hints'));
25
+ console.log(chalk_1.default.gray('─'.repeat(60)));
26
+ console.log(chalk_1.default.yellow('Command:'), chalk_1.default.white('rnsup view [options]'));
27
+ console.log();
28
+ console.log(chalk_1.default.yellow('Input options (when prompted):'));
29
+ console.log(' ' + chalk_1.default.white('. or root') + chalk_1.default.gray(' → Show entire project (all folders/files)'));
30
+ console.log(' ' + chalk_1.default.white('src') + chalk_1.default.gray(' → Show only src/ directory'));
31
+ console.log();
32
+ console.log(chalk_1.default.yellow('Command flags:'));
33
+ console.log(' ' + chalk_1.default.white('-p, --pretty') + chalk_1.default.gray(' → Show with icons, colors, and file sizes'));
34
+ console.log(' ' + chalk_1.default.white('--time') + chalk_1.default.gray(' → Show file/folder creation date and time'));
35
+ console.log();
36
+ console.log(chalk_1.default.yellow('Examples:'));
37
+ console.log(' ' + chalk_1.default.white('rnsup view') + chalk_1.default.gray(' → Raw structure (no icons)'));
38
+ console.log(' ' + chalk_1.default.white('rnsup view -p') + chalk_1.default.gray(' → Pretty view with icons & colors'));
39
+ console.log(' ' + chalk_1.default.white('rnsup view --time') + chalk_1.default.gray(' → Show with timestamps'));
40
+ console.log(' ' + chalk_1.default.white('rnsup view -p --time') + chalk_1.default.gray(' → Pretty view + timestamps'));
41
+ console.log(chalk_1.default.gray('─'.repeat(60)));
42
+ console.log();
43
+ }
44
+ const { viewTarget } = await inquirer_1.default.prompt([
45
+ {
46
+ type: 'list',
47
+ name: 'viewTarget',
48
+ message: 'What would you like to view?',
49
+ choices: [
50
+ { name: '📂 Root level (entire project)', value: 'root' },
51
+ { name: '📂 Inside src/ folder only', value: 'src' }
52
+ ]
53
+ }
54
+ ]);
55
+ let targetPath = process.cwd();
56
+ let displayLocation = 'root';
57
+ if (viewTarget === 'src') {
58
+ targetPath = path_1.default.join(process.cwd(), 'src');
59
+ displayLocation = 'src';
60
+ }
61
+ // Show colored header
62
+ console.log('\n' + chalk_1.default.cyan.bold('📋 Directory Structure'));
63
+ console.log(chalk_1.default.gray('─'.repeat(60)));
64
+ console.log(chalk_1.default.yellow('Location: '), chalk_1.default.white(displayLocation));
65
+ console.log(chalk_1.default.yellow('Mode: '), pretty ? chalk_1.default.magenta('Pretty') : chalk_1.default.dim('Raw'));
66
+ if (showTime) {
67
+ console.log(chalk_1.default.yellow('Time: '), chalk_1.default.magenta('Enabled'));
68
+ }
69
+ console.log(chalk_1.default.gray('─'.repeat(60)));
70
+ console.log();
71
+ // Build and display tree
72
+ const nodes = await (0, treeGenerator_1.buildTree)(targetPath, 10);
73
+ if (nodes.length === 0) {
74
+ console.log(chalk_1.default.yellow('No files or folders found in this directory.'));
75
+ }
76
+ else {
77
+ const formattedTree = (0, treeGenerator_1.formatTree)(nodes, { pretty, showTime });
78
+ console.log(formattedTree);
79
+ }
80
+ // Footer with hints
81
+ console.log(chalk_1.default.gray('─'.repeat(60)));
82
+ if (pretty) {
83
+ console.log(chalk_1.default.dim('📁 Cyan = folders | Colors = file types (blue=.ts, green=.json, etc)'));
84
+ }
85
+ console.log(chalk_1.default.dim('💡 Tip: You can copy the structure above for documentation'));
86
+ console.log();
87
+ }
88
+ catch (err) {
89
+ (0, handleCancel_1.handleCancel)(err);
90
+ }
91
+ }
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ const setup_1 = require("./commands/setup");
5
5
  const generateScreen_1 = require("./commands/generateScreen");
6
6
  const generateComponent_1 = require("./commands/generateComponent");
7
7
  const generateFolder_1 = require("./commands/generateFolder");
8
+ const viewStructure_1 = require("./commands/viewStructure");
8
9
  const program = new commander_1.Command();
9
10
  program
10
11
  .name('rnsup')
@@ -15,6 +16,14 @@ program
15
16
  .command('setup')
16
17
  .description('Configure React Native project')
17
18
  .action(setup_1.runSetup);
19
+ /* ---------- View Structure ---------- */
20
+ program
21
+ .command('view')
22
+ .alias('v')
23
+ .description('View project folder structure')
24
+ .option('-p, --pretty', 'Show with icons, colors and file sizes')
25
+ .option('--time', 'Show file/folder creation date and time')
26
+ .action(viewStructure_1.viewStructure);
18
27
  /* ---------- Generator Root ---------- */
19
28
  const generate = new commander_1.Command('generate')
20
29
  .alias('g')
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getComponentTemplate = getComponentTemplate;
4
+ function getComponentTemplate(name, type) {
5
+ switch (type) {
6
+ case 'container':
7
+ return containerComponentTemplate(name);
8
+ default:
9
+ return presentationalComponentTemplate(name);
10
+ }
11
+ }
12
+ function presentationalComponentTemplate(name) {
13
+ return `import React from 'react';
14
+ import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native';
15
+
16
+ interface Props {
17
+ title?: string;
18
+ children?: React.ReactNode;
19
+ style?: ViewStyle;
20
+ }
21
+
22
+ const ${name}: React.FC<Props> = ({ title, children, style }) => {
23
+ return (
24
+ <View style={[styles.container, style]}>
25
+ {title && <Text style={styles.title}>{title}</Text>}
26
+ {children}
27
+ </View>
28
+ );
29
+ };
30
+
31
+ export default ${name};
32
+
33
+ const styles = StyleSheet.create({
34
+ container: {
35
+ paddingHorizontal: 16,
36
+ paddingVertical: 12,
37
+ },
38
+ title: {
39
+ fontSize: 16,
40
+ fontWeight: '600',
41
+ marginBottom: 8,
42
+ },
43
+ });
44
+ `;
45
+ }
46
+ function containerComponentTemplate(name) {
47
+ return `import React, { useState } from 'react';
48
+ import { View, StyleSheet, ViewStyle } from 'react-native';
49
+ import { useNavigation } from '@react-navigation/native';
50
+
51
+ interface Props {
52
+ style?: ViewStyle;
53
+ children?: React.ReactNode;
54
+ }
55
+
56
+ interface State {
57
+ loading: boolean;
58
+ error: string | null;
59
+ }
60
+
61
+ const ${name}: React.FC<Props> = ({ style, children }) => {
62
+ const navigation = useNavigation();
63
+ const [state, setState] = useState<State>({ loading: false, error: null });
64
+
65
+ React.useEffect(() => {
66
+ // TODO: Initialize component data
67
+ }, []);
68
+
69
+ return (
70
+ <View style={[styles.container, style]}>
71
+ {state.loading ? (
72
+ <View style={styles.centerContent}>
73
+ {/* Loading indicator */}
74
+ </View>
75
+ ) : state.error ? (
76
+ <View style={styles.centerContent}>
77
+ {/* Error display */}
78
+ </View>
79
+ ) : (
80
+ children
81
+ )}
82
+ </View>
83
+ );
84
+ };
85
+
86
+ export default ${name};
87
+
88
+ const styles = StyleSheet.create({
89
+ container: {
90
+ flex: 1,
91
+ },
92
+ centerContent: {
93
+ flex: 1,
94
+ alignItems: 'center',
95
+ justifyContent: 'center',
96
+ },
97
+ });
98
+ `;
99
+ }
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getScreenTemplate = getScreenTemplate;
4
+ function getScreenTemplate(name, type) {
5
+ switch (type) {
6
+ case 'list':
7
+ return listScreenTemplate(name);
8
+ case 'form':
9
+ return formScreenTemplate(name);
10
+ case 'detail':
11
+ return detailScreenTemplate(name);
12
+ default:
13
+ return basicScreenTemplate(name);
14
+ }
15
+ }
16
+ function basicScreenTemplate(name) {
17
+ return `import React from 'react';
18
+ import { View, Text, StyleSheet } from 'react-native';
19
+ import { useNavigation } from '@react-navigation/native';
20
+
21
+ const ${name} = () => {
22
+ const navigation = useNavigation();
23
+
24
+ return (
25
+ <View style={styles.container}>
26
+ <Text style={styles.title}>${name}</Text>
27
+ </View>
28
+ );
29
+ };
30
+
31
+ export default ${name};
32
+
33
+ const styles = StyleSheet.create({
34
+ container: {
35
+ flex: 1,
36
+ alignItems: 'center',
37
+ justifyContent: 'center',
38
+ paddingHorizontal: 16,
39
+ },
40
+ title: {
41
+ fontSize: 24,
42
+ fontWeight: 'bold',
43
+ },
44
+ });
45
+ `;
46
+ }
47
+ function listScreenTemplate(name) {
48
+ return `import React, { useState } from 'react';
49
+ import { View, Text, FlatList, StyleSheet, ActivityIndicator } from 'react-native';
50
+ import { useNavigation } from '@react-navigation/native';
51
+
52
+ interface Item {
53
+ id: string;
54
+ title: string;
55
+ }
56
+
57
+ const ${name} = () => {
58
+ const navigation = useNavigation();
59
+ const [items, setItems] = useState<Item[]>([]);
60
+ const [loading, setLoading] = useState(false);
61
+
62
+ const renderItem = ({ item }: { item: Item }) => (
63
+ <View style={styles.itemContainer}>
64
+ <Text style={styles.itemTitle}>{item.title}</Text>
65
+ </View>
66
+ );
67
+
68
+ return (
69
+ <View style={styles.container}>
70
+ <Text style={styles.title}>${name}</Text>
71
+ {loading ? (
72
+ <ActivityIndicator size="large" color="#007AFF" />
73
+ ) : (
74
+ <FlatList
75
+ data={items}
76
+ renderItem={renderItem}
77
+ keyExtractor={(item) => item.id}
78
+ contentContainerStyle={styles.listContent}
79
+ />
80
+ )}
81
+ </View>
82
+ );
83
+ };
84
+
85
+ export default ${name};
86
+
87
+ const styles = StyleSheet.create({
88
+ container: {
89
+ flex: 1,
90
+ paddingHorizontal: 16,
91
+ paddingTop: 12,
92
+ },
93
+ title: {
94
+ fontSize: 24,
95
+ fontWeight: 'bold',
96
+ marginBottom: 16,
97
+ },
98
+ listContent: {
99
+ paddingBottom: 16,
100
+ },
101
+ itemContainer: {
102
+ paddingVertical: 12,
103
+ paddingHorizontal: 12,
104
+ marginBottom: 8,
105
+ backgroundColor: '#f5f5f5',
106
+ borderRadius: 8,
107
+ },
108
+ itemTitle: {
109
+ fontSize: 16,
110
+ fontWeight: '500',
111
+ },
112
+ });
113
+ `;
114
+ }
115
+ function formScreenTemplate(name) {
116
+ return `import React, { useState } from 'react';
117
+ import { View, Text, TextInput, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
118
+ import { useNavigation } from '@react-navigation/native';
119
+
120
+ interface FormData {
121
+ name: string;
122
+ email: string;
123
+ }
124
+
125
+ const ${name} = () => {
126
+ const navigation = useNavigation();
127
+ const [formData, setFormData] = useState<FormData>({ name: '', email: '' });
128
+ const [loading, setLoading] = useState(false);
129
+
130
+ const handleSubmit = async () => {
131
+ setLoading(true);
132
+ try {
133
+ // TODO: Submit form data
134
+ console.log('Form data:', formData);
135
+ } finally {
136
+ setLoading(false);
137
+ }
138
+ };
139
+
140
+ return (
141
+ <ScrollView style={styles.container}>
142
+ <Text style={styles.title}>${name}</Text>
143
+
144
+ <View style={styles.formGroup}>
145
+ <Text style={styles.label}>Name</Text>
146
+ <TextInput
147
+ style={styles.input}
148
+ placeholder="Enter name"
149
+ value={formData.name}
150
+ onChangeText={(text) => setFormData({ ...formData, name: text })}
151
+ />
152
+ </View>
153
+
154
+ <View style={styles.formGroup}>
155
+ <Text style={styles.label}>Email</Text>
156
+ <TextInput
157
+ style={styles.input}
158
+ placeholder="Enter email"
159
+ value={formData.email}
160
+ onChangeText={(text) => setFormData({ ...formData, email: text })}
161
+ keyboardType="email-address"
162
+ />
163
+ </View>
164
+
165
+ <TouchableOpacity
166
+ style={[styles.button, loading && styles.buttonDisabled]}
167
+ onPress={handleSubmit}
168
+ disabled={loading}
169
+ >
170
+ <Text style={styles.buttonText}>{loading ? 'Submitting...' : 'Submit'}</Text>
171
+ </TouchableOpacity>
172
+ </ScrollView>
173
+ );
174
+ };
175
+
176
+ export default ${name};
177
+
178
+ const styles = StyleSheet.create({
179
+ container: {
180
+ flex: 1,
181
+ paddingHorizontal: 16,
182
+ paddingTop: 16,
183
+ },
184
+ title: {
185
+ fontSize: 24,
186
+ fontWeight: 'bold',
187
+ marginBottom: 24,
188
+ },
189
+ formGroup: {
190
+ marginBottom: 16,
191
+ },
192
+ label: {
193
+ fontSize: 14,
194
+ fontWeight: '600',
195
+ marginBottom: 8,
196
+ color: '#333',
197
+ },
198
+ input: {
199
+ borderWidth: 1,
200
+ borderColor: '#ddd',
201
+ borderRadius: 8,
202
+ paddingHorizontal: 12,
203
+ paddingVertical: 10,
204
+ fontSize: 14,
205
+ },
206
+ button: {
207
+ backgroundColor: '#007AFF',
208
+ borderRadius: 8,
209
+ paddingVertical: 12,
210
+ alignItems: 'center',
211
+ marginTop: 24,
212
+ marginBottom: 30,
213
+ },
214
+ buttonDisabled: {
215
+ opacity: 0.6,
216
+ },
217
+ buttonText: {
218
+ color: '#fff',
219
+ fontSize: 16,
220
+ fontWeight: '600',
221
+ },
222
+ });
223
+ `;
224
+ }
225
+ function detailScreenTemplate(name) {
226
+ return `import React, { useState } from 'react';
227
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator } from 'react-native';
228
+ import { useNavigation, useRoute } from '@react-navigation/native';
229
+
230
+ interface DetailData {
231
+ id: string;
232
+ title: string;
233
+ description: string;
234
+ status: string;
235
+ }
236
+
237
+ const ${name} = () => {
238
+ const navigation = useNavigation();
239
+ const route = useRoute<any>();
240
+ const [data, setData] = useState<DetailData | null>(null);
241
+ const [loading, setLoading] = useState(true);
242
+
243
+ React.useEffect(() => {
244
+ // TODO: Fetch detail data
245
+ setLoading(false);
246
+ }, []);
247
+
248
+ if (loading) {
249
+ return (
250
+ <View style={styles.centerContainer}>
251
+ <ActivityIndicator size="large" color="#007AFF" />
252
+ </View>
253
+ );
254
+ }
255
+
256
+ if (!data) {
257
+ return (
258
+ <View style={styles.centerContainer}>
259
+ <Text style={styles.errorText}>No data found</Text>
260
+ </View>
261
+ );
262
+ }
263
+
264
+ return (
265
+ <ScrollView style={styles.container}>
266
+ <Text style={styles.title}>{data.title}</Text>
267
+
268
+ <View style={styles.section}>
269
+ <Text style={styles.sectionLabel}>Description</Text>
270
+ <Text style={styles.description}>{data.description}</Text>
271
+ </View>
272
+
273
+ <View style={styles.section}>
274
+ <Text style={styles.sectionLabel}>Status</Text>
275
+ <Text style={[styles.status, { color: data.status === 'active' ? '#4CAF50' : '#FF9800' }]}>
276
+ {data.status}
277
+ </Text>
278
+ </View>
279
+
280
+ <TouchableOpacity style={styles.editButton}>
281
+ <Text style={styles.editButtonText}>Edit</Text>
282
+ </TouchableOpacity>
283
+ </ScrollView>
284
+ );
285
+ };
286
+
287
+ export default ${name};
288
+
289
+ const styles = StyleSheet.create({
290
+ container: {
291
+ flex: 1,
292
+ paddingHorizontal: 16,
293
+ paddingTop: 16,
294
+ },
295
+ centerContainer: {
296
+ flex: 1,
297
+ alignItems: 'center',
298
+ justifyContent: 'center',
299
+ },
300
+ title: {
301
+ fontSize: 24,
302
+ fontWeight: 'bold',
303
+ marginBottom: 24,
304
+ },
305
+ section: {
306
+ marginBottom: 24,
307
+ },
308
+ sectionLabel: {
309
+ fontSize: 14,
310
+ fontWeight: '600',
311
+ marginBottom: 8,
312
+ color: '#666',
313
+ },
314
+ description: {
315
+ fontSize: 14,
316
+ lineHeight: 20,
317
+ color: '#333',
318
+ },
319
+ status: {
320
+ fontSize: 14,
321
+ fontWeight: '600',
322
+ },
323
+ errorText: {
324
+ fontSize: 16,
325
+ color: '#f44336',
326
+ },
327
+ editButton: {
328
+ backgroundColor: '#007AFF',
329
+ borderRadius: 8,
330
+ paddingVertical: 12,
331
+ alignItems: 'center',
332
+ marginTop: 24,
333
+ marginBottom: 30,
334
+ },
335
+ editButtonText: {
336
+ color: '#fff',
337
+ fontSize: 16,
338
+ fontWeight: '600',
339
+ },
340
+ });
341
+ `;
342
+ }
@@ -4,31 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.selectOption = selectOption;
7
- const readline_1 = __importDefault(require("readline"));
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
8
  /**
9
- * Numeric select prompt
9
+ * Interactive list prompt using inquirer
10
10
  * Returns a typed value instead of raw string
11
11
  */
12
- async function selectOption(message, options) {
13
- return new Promise((resolve) => {
14
- console.log('\n\x1b[1;36m' + message + '\x1b[0m');
15
- options.forEach((opt, i) => {
16
- console.log(`${i + 1}) ${opt}`);
17
- });
18
- const rl = readline_1.default.createInterface({
19
- input: process.stdin,
20
- output: process.stdout
21
- });
22
- rl.question('\x1b[1;33mEnter choice number: \x1b[0m', (answer) => {
23
- const index = Number(answer) - 1;
24
- rl.close();
25
- if (index >= 0 && index < options.length) {
26
- resolve(options[index]);
27
- }
28
- else {
29
- console.log('\x1b[1;31mInvalid selection. Defaulting to first option.\x1b[0m');
30
- resolve(options[0]);
31
- }
32
- });
33
- });
12
+ async function selectOption(message, options, defaultValue) {
13
+ const { selected } = await inquirer_1.default.prompt([
14
+ {
15
+ type: 'list',
16
+ name: 'selected',
17
+ message: message,
18
+ choices: [...options],
19
+ default: defaultValue || options[0]
20
+ }
21
+ ]);
22
+ return selected;
34
23
  }