@burger-api/cli 0.6.6 → 0.7.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.
@@ -1,229 +1,229 @@
1
- /**
2
- * Create Command
3
- *
4
- * This command helps users create a new Burger API project.
5
- * It asks simple questions and sets up everything they need to get started.
6
- *
7
- * We use @clack/prompts for beautiful, user-friendly interactive prompts.
8
- */
9
-
10
- import { Command } from 'commander';
11
- import * as clack from '@clack/prompts';
12
- import { existsSync } from 'fs';
13
- import { join } from 'path';
14
- import type { CreateOptions } from '../types/index';
15
- import { createProject, installDependencies } from '../utils/templates';
16
- import {
17
- success,
18
- error as logError,
19
- info,
20
- newline,
21
- header,
22
- command,
23
- highlight,
24
- } from '../utils/logger';
25
-
26
- /**
27
- * Create the "create" command
28
- * This is what runs when users type: burger-api create <projectName>
29
- */
30
- /**
31
- * Validate project name for filesystem compatibility
32
- * @param name - Project name to validate
33
- * @returns Error message if invalid, undefined if valid
34
- */
35
- function validateProjectName(name: string): string | undefined {
36
- if (!name) return 'Project name is required';
37
- if (name.length > 100)
38
- return 'Project name is too long (max 100 characters)';
39
- if (/^[.-]/.test(name))
40
- return 'Project name cannot start with a dot or dash';
41
- if (/[<>:"/\\|?*\x00-\x1F]/.test(name)) {
42
- return 'Project name contains invalid characters';
43
- }
44
- if (/\s/.test(name)) return 'Project name cannot contain spaces';
45
- return undefined;
46
- }
47
-
48
- export const createCommand = new Command('create')
49
- .description('Create a new Burger API project')
50
- .argument('<project-name>', 'Name of your project')
51
- .action(async (projectName: string) => {
52
- // Start with a nice intro
53
- clack.intro('Create a new BurgerAPI project');
54
-
55
- try {
56
- // Validate project name
57
- const nameError = validateProjectName(projectName);
58
- if (nameError) {
59
- clack.outro('Invalid project name');
60
- logError(nameError);
61
- process.exit(1);
62
- }
63
-
64
- // Check if directory already exists
65
- const targetDir = join(process.cwd(), projectName);
66
- if (existsSync(targetDir)) {
67
- clack.outro('Directory already exists!');
68
- logError(`A directory named "${projectName}" already exists.`);
69
- process.exit(1);
70
- }
71
-
72
- // Ask user questions to configure the project
73
- const options = await askQuestions(projectName);
74
-
75
- // User cancelled
76
- if (clack.isCancel(options)) {
77
- clack.outro('Operation cancelled');
78
- process.exit(0);
79
- }
80
-
81
- // Show what we're about to create
82
- info('Creating project with the following configuration:');
83
- newline();
84
- console.log(` Name: ${projectName}`);
85
- if (options.useApi) {
86
- console.log(` API Routes: ${options.apiDir || 'api'}`);
87
- }
88
- if (options.usePages) {
89
- console.log(` Page Routes: ${options.pageDir || 'pages'}`);
90
- }
91
- newline();
92
-
93
- // Create the project
94
- await createProject(targetDir, options);
95
-
96
- // Install dependencies
97
- await installDependencies(targetDir);
98
-
99
- // Success! Show them what to do next
100
- clack.outro('Project created successfully!');
101
- newline();
102
- header('Next Steps');
103
- console.log(` 1. Navigate to your project:`);
104
- command(`cd ${projectName}`);
105
- newline();
106
- console.log(` 2. Start the development server:`);
107
- command('bun run dev');
108
- newline();
109
- console.log(` 3. Open your browser:`);
110
- console.log(` ${highlight('http://localhost:4000')}`);
111
- newline();
112
- console.log(` 4. Add middleware (optional):`);
113
- command('burger-api add cors logger');
114
- newline();
115
- success('Happy coding!');
116
- } catch (err) {
117
- clack.outro('Failed to create project');
118
- logError(err instanceof Error ? err.message : 'Unknown error');
119
- process.exit(1);
120
- }
121
- });
122
-
123
- /**
124
- * Ask user questions to configure their project
125
- * Uses @clack/prompts for beautiful interactive prompts
126
- *
127
- * @param projectName - Name of the project
128
- * @returns Configuration options from user answers
129
- */
130
- async function askQuestions(projectName: string): Promise<CreateOptions> {
131
- // Ask all questions in a nice flow
132
- const answers = await clack.group(
133
- {
134
- // Question 1: Do you need API routes?
135
- useApi: () =>
136
- clack.confirm({
137
- message: 'Do you need API routes?',
138
- initialValue: true,
139
- }),
140
-
141
- // Question 2: API directory (only if they said yes to API)
142
- apiDir: ({ results }) =>
143
- results.useApi
144
- ? clack.text({
145
- message: 'API directory name:',
146
- initialValue: 'api',
147
- placeholder: 'api',
148
- validate: (value) => {
149
- if (!value)
150
- return 'Please enter a directory name';
151
- if (value.includes(' '))
152
- return 'Directory name cannot contain spaces';
153
- },
154
- })
155
- : Promise.resolve('api'),
156
-
157
- // Question 3: API prefix (only if they said yes to API)
158
- apiPrefix: ({ results }) =>
159
- results.useApi
160
- ? clack.text({
161
- message: 'API route prefix:',
162
- initialValue: '/api',
163
- placeholder: '/api',
164
- })
165
- : Promise.resolve('/api'),
166
-
167
- // Question 4: Debug mode (only if they said yes to API)
168
- debug: ({ results }) =>
169
- results.useApi
170
- ? clack.confirm({
171
- message: 'Enable debug mode?',
172
- initialValue: false,
173
- })
174
- : Promise.resolve(false),
175
-
176
- // Question 5: Do you need Page routes?
177
- usePages: () =>
178
- clack.confirm({
179
- message: 'Do you need Page routes?',
180
- initialValue: false,
181
- }),
182
-
183
- // Question 6: Page directory (only if they said yes to Pages)
184
- pageDir: ({ results }) =>
185
- results.usePages
186
- ? clack.text({
187
- message: 'Page directory name:',
188
- initialValue: 'pages',
189
- placeholder: 'pages',
190
- validate: (value) => {
191
- if (!value)
192
- return 'Please enter a directory name';
193
- if (value.includes(' '))
194
- return 'Directory name cannot contain spaces';
195
- },
196
- })
197
- : Promise.resolve('pages'),
198
-
199
- // Question 7: Page prefix (only if they said yes to Pages)
200
- pagePrefix: ({ results }) =>
201
- results.usePages
202
- ? clack.text({
203
- message: 'Page route prefix:',
204
- initialValue: '/',
205
- placeholder: '/',
206
- })
207
- : Promise.resolve('/'),
208
- },
209
- {
210
- // Callback when user cancels (Ctrl+C)
211
- onCancel: () => {
212
- clack.cancel('Operation cancelled');
213
- process.exit(0);
214
- },
215
- }
216
- );
217
-
218
- // Return the configuration
219
- return {
220
- name: projectName,
221
- useApi: answers.useApi as boolean,
222
- apiDir: answers.apiDir as string | undefined,
223
- apiPrefix: answers.apiPrefix as string | undefined,
224
- debug: answers.debug as boolean | undefined,
225
- usePages: answers.usePages as boolean,
226
- pageDir: answers.pageDir as string | undefined,
227
- pagePrefix: answers.pagePrefix as string | undefined,
228
- };
229
- }
1
+ /**
2
+ * Create Command
3
+ *
4
+ * This command helps users create a new Burger API project.
5
+ * It asks simple questions and sets up everything they need to get started.
6
+ *
7
+ * We use @clack/prompts for beautiful, user-friendly interactive prompts.
8
+ */
9
+
10
+ import { Command } from 'commander';
11
+ import * as clack from '@clack/prompts';
12
+ import { existsSync } from 'fs';
13
+ import { join } from 'path';
14
+ import type { CreateOptions } from '../types/index';
15
+ import { createProject, installDependencies } from '../utils/templates';
16
+ import {
17
+ success,
18
+ error as logError,
19
+ info,
20
+ newline,
21
+ header,
22
+ command,
23
+ highlight,
24
+ } from '../utils/logger';
25
+
26
+ /**
27
+ * Create the "create" command
28
+ * This is what runs when users type: burger-api create <projectName>
29
+ */
30
+ /**
31
+ * Validate project name for filesystem compatibility
32
+ * @param name - Project name to validate
33
+ * @returns Error message if invalid, undefined if valid
34
+ */
35
+ function validateProjectName(name: string): string | undefined {
36
+ if (!name) return 'Project name is required';
37
+ if (name.length > 100)
38
+ return 'Project name is too long (max 100 characters)';
39
+ if (/^[.-]/.test(name))
40
+ return 'Project name cannot start with a dot or dash';
41
+ if (/[<>:"/\\|?*\x00-\x1F]/.test(name)) {
42
+ return 'Project name contains invalid characters';
43
+ }
44
+ if (/\s/.test(name)) return 'Project name cannot contain spaces';
45
+ return undefined;
46
+ }
47
+
48
+ export const createCommand = new Command('create')
49
+ .description('Create a new Burger API project')
50
+ .argument('<project-name>', 'Name of your project')
51
+ .action(async (projectName: string) => {
52
+ // Start with a nice intro
53
+ clack.intro('Create a new BurgerAPI project');
54
+
55
+ try {
56
+ // Validate project name
57
+ const nameError = validateProjectName(projectName);
58
+ if (nameError) {
59
+ clack.outro('Invalid project name');
60
+ logError(nameError);
61
+ process.exit(1);
62
+ }
63
+
64
+ // Check if directory already exists
65
+ const targetDir = join(process.cwd(), projectName);
66
+ if (existsSync(targetDir)) {
67
+ clack.outro('Directory already exists!');
68
+ logError(`A directory named "${projectName}" already exists.`);
69
+ process.exit(1);
70
+ }
71
+
72
+ // Ask user questions to configure the project
73
+ const options = await askQuestions(projectName);
74
+
75
+ // User cancelled
76
+ if (clack.isCancel(options)) {
77
+ clack.outro('Operation cancelled');
78
+ process.exit(0);
79
+ }
80
+
81
+ // Show what we're about to create
82
+ info('Creating project with the following configuration:');
83
+ newline();
84
+ console.log(` Name: ${projectName}`);
85
+ if (options.useApi) {
86
+ console.log(` API Routes: ${options.apiDir || 'api'}`);
87
+ }
88
+ if (options.usePages) {
89
+ console.log(` Page Routes: ${options.pageDir || 'pages'}`);
90
+ }
91
+ newline();
92
+
93
+ // Create the project
94
+ await createProject(targetDir, options);
95
+
96
+ // Install dependencies
97
+ await installDependencies(targetDir);
98
+
99
+ // Success! Show them what to do next
100
+ clack.outro('Project created successfully!');
101
+ newline();
102
+ header('Next Steps');
103
+ console.log(` 1. Navigate to your project:`);
104
+ command(`cd ${projectName}`);
105
+ newline();
106
+ console.log(` 2. Start the development server:`);
107
+ command('bun run dev');
108
+ newline();
109
+ console.log(` 3. Open your browser:`);
110
+ console.log(` ${highlight('http://localhost:4000')}`);
111
+ newline();
112
+ console.log(` 4. Add middleware (optional):`);
113
+ command('burger-api add cors logger');
114
+ newline();
115
+ success('Happy coding!');
116
+ } catch (err) {
117
+ clack.outro('Failed to create project');
118
+ logError(err instanceof Error ? err.message : 'Unknown error');
119
+ process.exit(1);
120
+ }
121
+ });
122
+
123
+ /**
124
+ * Ask user questions to configure their project
125
+ * Uses @clack/prompts for beautiful interactive prompts
126
+ *
127
+ * @param projectName - Name of the project
128
+ * @returns Configuration options from user answers
129
+ */
130
+ async function askQuestions(projectName: string): Promise<CreateOptions> {
131
+ // Ask all questions in a nice flow
132
+ const answers = await clack.group(
133
+ {
134
+ // Question 1: Do you need API routes?
135
+ useApi: () =>
136
+ clack.confirm({
137
+ message: 'Do you need API routes?',
138
+ initialValue: true,
139
+ }),
140
+
141
+ // Question 2: API directory (only if they said yes to API)
142
+ apiDir: ({ results }) =>
143
+ results.useApi
144
+ ? clack.text({
145
+ message: 'API directory name:',
146
+ initialValue: 'api',
147
+ placeholder: 'api',
148
+ validate: (value) => {
149
+ if (!value)
150
+ return 'Please enter a directory name';
151
+ if (value.includes(' '))
152
+ return 'Directory name cannot contain spaces';
153
+ },
154
+ })
155
+ : Promise.resolve('api'),
156
+
157
+ // Question 3: API prefix (only if they said yes to API)
158
+ apiPrefix: ({ results }) =>
159
+ results.useApi
160
+ ? clack.text({
161
+ message: 'API route prefix:',
162
+ initialValue: '/api',
163
+ placeholder: '/api',
164
+ })
165
+ : Promise.resolve('/api'),
166
+
167
+ // Question 4: Debug mode (only if they said yes to API)
168
+ debug: ({ results }) =>
169
+ results.useApi
170
+ ? clack.confirm({
171
+ message: 'Enable debug mode?',
172
+ initialValue: false,
173
+ })
174
+ : Promise.resolve(false),
175
+
176
+ // Question 5: Do you need Page routes?
177
+ usePages: () =>
178
+ clack.confirm({
179
+ message: 'Do you need Page routes?',
180
+ initialValue: false,
181
+ }),
182
+
183
+ // Question 6: Page directory (only if they said yes to Pages)
184
+ pageDir: ({ results }) =>
185
+ results.usePages
186
+ ? clack.text({
187
+ message: 'Page directory name:',
188
+ initialValue: 'pages',
189
+ placeholder: 'pages',
190
+ validate: (value) => {
191
+ if (!value)
192
+ return 'Please enter a directory name';
193
+ if (value.includes(' '))
194
+ return 'Directory name cannot contain spaces';
195
+ },
196
+ })
197
+ : Promise.resolve('pages'),
198
+
199
+ // Question 7: Page prefix (only if they said yes to Pages)
200
+ pagePrefix: ({ results }) =>
201
+ results.usePages
202
+ ? clack.text({
203
+ message: 'Page route prefix:',
204
+ initialValue: '/',
205
+ placeholder: '/',
206
+ })
207
+ : Promise.resolve('/'),
208
+ },
209
+ {
210
+ // Callback when user cancels (Ctrl+C)
211
+ onCancel: () => {
212
+ clack.cancel('Operation cancelled');
213
+ process.exit(0);
214
+ },
215
+ }
216
+ );
217
+
218
+ // Return the configuration
219
+ return {
220
+ name: projectName,
221
+ useApi: answers.useApi as boolean,
222
+ apiDir: answers.apiDir as string | undefined,
223
+ apiPrefix: answers.apiPrefix as string | undefined,
224
+ debug: answers.debug as boolean | undefined,
225
+ usePages: answers.usePages as boolean,
226
+ pageDir: answers.pageDir as string | undefined,
227
+ pagePrefix: answers.pagePrefix as string | undefined,
228
+ };
229
+ }
@@ -1,88 +1,88 @@
1
- /**
2
- * List Command
3
- *
4
- * Shows users all available middleware they can add to their project.
5
- * Fetches the list from GitHub and displays it in a nice table format.
6
- *
7
- * Example: burger-api list
8
- */
9
-
10
- import { Command } from 'commander';
11
- import { getMiddlewareList, getMiddlewareInfo } from '../utils/github';
12
- import {
13
- header,
14
- spinner,
15
- error as logError,
16
- table,
17
- newline,
18
- info,
19
- dim,
20
- command,
21
- } from '../utils/logger';
22
-
23
- /**
24
- * Create the "list" command
25
- * This shows all available middleware from the ecosystem
26
- */
27
- export const listCommand = new Command('list')
28
- .description('Show available middleware from the ecosystem')
29
- .alias('ls') // Allow users to type "burger-api ls" too
30
- .action(async () => {
31
- // Show a spinner while fetching from GitHub
32
- const spin = spinner('Fetching middleware list from GitHub...');
33
-
34
- try {
35
- // Get the list of middleware names
36
- const middlewareNames = await getMiddlewareList();
37
-
38
- // Fetch details for each middleware (in parallel for speed!)
39
- const middlewareDetails = await Promise.all(
40
- middlewareNames.map((name) =>
41
- getMiddlewareInfo(name).catch(() => ({
42
- name,
43
- description: 'No description available',
44
- path: '',
45
- files: [],
46
- }))
47
- )
48
- );
49
-
50
- spin.stop('Found available middleware!');
51
- newline();
52
-
53
- // Display header
54
- header('Available Middleware');
55
-
56
- // Create table data
57
- const tableData: string[][] = [
58
- ['Name', 'Description'],
59
- ...middlewareDetails.map((m) => [
60
- m.name,
61
- m.description.length > 60
62
- ? m.description.substring(0, 57) + '...'
63
- : m.description,
64
- ]),
65
- ];
66
-
67
- // Show the table
68
- table(tableData);
69
- newline();
70
-
71
- // Show usage instructions
72
- info('To add middleware to your project, run:');
73
- command('burger-api add <middleware-name>');
74
- newline();
75
- dim('Example: burger-api add cors logger rate-limiter');
76
- newline();
77
- } catch (err) {
78
- spin.stop('Failed to fetch middleware list', true);
79
- logError(
80
- err instanceof Error
81
- ? err.message
82
- : 'Could not connect to GitHub'
83
- );
84
- newline();
85
- info('Please check your internet connection and try again.');
86
- process.exit(1);
87
- }
88
- });
1
+ /**
2
+ * List Command
3
+ *
4
+ * Shows users all available middleware they can add to their project.
5
+ * Fetches the list from GitHub and displays it in a nice table format.
6
+ *
7
+ * Example: burger-api list
8
+ */
9
+
10
+ import { Command } from 'commander';
11
+ import { getMiddlewareList, getMiddlewareInfo } from '../utils/github';
12
+ import {
13
+ header,
14
+ spinner,
15
+ error as logError,
16
+ table,
17
+ newline,
18
+ info,
19
+ dim,
20
+ command,
21
+ } from '../utils/logger';
22
+
23
+ /**
24
+ * Create the "list" command
25
+ * This shows all available middleware from the ecosystem
26
+ */
27
+ export const listCommand = new Command('list')
28
+ .description('Show available middleware from the ecosystem')
29
+ .alias('ls') // Allow users to type "burger-api ls" too
30
+ .action(async () => {
31
+ // Show a spinner while fetching from GitHub
32
+ const spin = spinner('Fetching middleware list from GitHub...');
33
+
34
+ try {
35
+ // Get the list of middleware names
36
+ const middlewareNames = await getMiddlewareList();
37
+
38
+ // Fetch details for each middleware (in parallel for speed!)
39
+ const middlewareDetails = await Promise.all(
40
+ middlewareNames.map((name) =>
41
+ getMiddlewareInfo(name).catch(() => ({
42
+ name,
43
+ description: 'No description available',
44
+ path: '',
45
+ files: [],
46
+ }))
47
+ )
48
+ );
49
+
50
+ spin.stop('Found available middleware!');
51
+ newline();
52
+
53
+ // Display header
54
+ header('Available Middleware');
55
+
56
+ // Create table data
57
+ const tableData: string[][] = [
58
+ ['Name', 'Description'],
59
+ ...middlewareDetails.map((m) => [
60
+ m.name,
61
+ m.description.length > 60
62
+ ? m.description.substring(0, 57) + '...'
63
+ : m.description,
64
+ ]),
65
+ ];
66
+
67
+ // Show the table
68
+ table(tableData);
69
+ newline();
70
+
71
+ // Show usage instructions
72
+ info('To add middleware to your project, run:');
73
+ command('burger-api add <middleware-name>');
74
+ newline();
75
+ dim('Example: burger-api add cors logger rate-limiter');
76
+ newline();
77
+ } catch (err) {
78
+ spin.stop('Failed to fetch middleware list', true);
79
+ logError(
80
+ err instanceof Error
81
+ ? err.message
82
+ : 'Could not connect to GitHub'
83
+ );
84
+ newline();
85
+ info('Please check your internet connection and try again.');
86
+ process.exit(1);
87
+ }
88
+ });