@enfyra/create-app 0.1.30

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.
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git checkout:*)"
5
+ ],
6
+ "deny": [],
7
+ "ask": []
8
+ }
9
+ }
package/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # Create Enfyra App
2
+
3
+ šŸš€ **The fastest way to create new Enfyra frontend applications**
4
+
5
+ Create Enfyra App is a CLI tool that instantly scaffolds new Enfyra frontend projects with all the essentials configured for you.
6
+
7
+ ## āš ļø Prerequisites
8
+
9
+ **Important:** You need to have an Enfyra backend running before creating your frontend application. The frontend will connect to your backend API.
10
+
11
+ šŸ“‹ **Set up your backend first:**
12
+ ```bash
13
+ npx @enfyra/create-server my-backend
14
+ ```
15
+
16
+ šŸ‘‰ **[Backend Setup Guide](https://www.npmjs.com/package/@enfyra/create-server)** - Complete instructions for setting up your Enfyra backend
17
+
18
+ ## Quick Start
19
+
20
+ ```bash
21
+ # Using npx (recommended)
22
+ npx @enfyra/create-app my-app
23
+
24
+ # Using yarn
25
+ yarn create @enfyra/app my-app
26
+
27
+ # Using pnpm
28
+ pnpm create @enfyra/app my-app
29
+
30
+ # Using bun
31
+ bun create @enfyra/app my-app
32
+
33
+ # Or install globally
34
+ npm install -g @enfyra/create-app
35
+ create-app my-app
36
+ ```
37
+
38
+ ## Demo
39
+
40
+ 🌐 **Live Demo**: [https://demo.enfyra.io](https://demo.enfyra.io)
41
+
42
+ ## What You Get
43
+
44
+ āœ… **Nuxt 3** application ready to go
45
+ āœ… **Enfyra SDK** pre-configured
46
+ āœ… **TypeScript** support
47
+ āœ… **Tailwind CSS** styling
48
+ āœ… **Environment** variables setup
49
+ āœ… **Dependencies** installed automatically
50
+
51
+ ## Requirements
52
+
53
+ - **Node.js** 20.0.0 or higher
54
+ - **Package manager**: npm (8+), yarn (1.22+), pnpm (7+), or bun (1+)
55
+
56
+ ## Usage
57
+
58
+ ### Create a new project
59
+ ```bash
60
+ npx @enfyra/create-app my-project
61
+ ```
62
+
63
+ ### Interactive setup
64
+ The CLI will guide you through:
65
+ - Package manager selection
66
+ - API endpoint configuration
67
+ - Development port setup
68
+
69
+ ### Environment Variables
70
+ After project creation, you can modify the `.env` file at any time to configure:
71
+ - API endpoints
72
+ - Port
73
+
74
+ The `.env` file is automatically created and can be customized for your specific needs.
75
+
76
+ ### Start developing
77
+ ```bash
78
+ cd my-project
79
+ npm run dev
80
+ ```
81
+
82
+ ## After Installation
83
+
84
+ Your new Enfyra app is ready! Here's what to do next:
85
+
86
+ ### Development
87
+ ```bash
88
+ npm run dev # Start development server
89
+ npm run build # Build for production
90
+ npm run preview # Preview production build
91
+ ```
92
+
93
+ ### Learn More
94
+
95
+ šŸ“– **[Complete Documentation](https://github.com/dothinh115/enfyra-app#readme)** - Full guide to building with Enfyra
96
+ šŸ”§ **[API Reference](https://github.com/dothinh115/enfyra-app/blob/main/docs/API.md)** - Backend integration
97
+ šŸŽØ **[UI Components](https://github.com/dothinh115/enfyra-app/blob/main/docs/COMPONENTS.md)** - Pre-built components
98
+ ⚔ **[Best Practices](https://github.com/dothinh115/enfyra-app/blob/main/docs/BEST_PRACTICES.md)** - Development guidelines
99
+
100
+ ## Support
101
+
102
+ Having issues? We're here to help:
103
+
104
+ - šŸ› [Report bugs](https://github.com/dothinh115/create-enfyra-app/issues)
105
+ - šŸ’¬ [Ask questions](https://github.com/dothinh115/enfyra-app/discussions)
106
+ - šŸ“§ [Email support](mailto:dothinh115@gmail.com)
107
+
108
+ ## Related
109
+
110
+ - **[Enfyra App](https://github.com/dothinh115/enfyra-app)** - The frontend template
111
+ - **[Enfyra BE](https://github.com/dothinh115/enfyra_be)** - Backend framework
112
+ - **[Create Enfyra Server](https://github.com/dothinh115/create-enfyra-server)** - Backend CLI
113
+
114
+ ---
115
+
116
+ Built by [dothinh115](https://github.com/dothinh115) • MIT License
@@ -0,0 +1,22 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ async function generateEnvFile(projectPath, config) {
5
+ const envContent = buildEnvContent(config);
6
+ const envPath = path.join(projectPath, '.env');
7
+
8
+ await fs.writeFile(envPath, envContent);
9
+ }
10
+
11
+ function buildEnvContent(config) {
12
+ const lines = [
13
+ `API_URL=${config.apiUrl}`,
14
+ `PORT=${config.port}`
15
+ ];
16
+
17
+ return lines.join('\n');
18
+ }
19
+
20
+ module.exports = {
21
+ generateEnvFile
22
+ };
@@ -0,0 +1,297 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const ora = require('ora');
5
+ const { spawn, execSync } = require('child_process');
6
+ const { downloadTemplate } = require('giget');
7
+ const { generateEnvFile } = require('./env-builder');
8
+
9
+ // Check available package managers with version validation
10
+ function detectPackageManagers() {
11
+ const managers = [];
12
+
13
+ // Check npm (minimum version 8.0.0)
14
+ try {
15
+ const npmVersion = execSync('npm --version', {
16
+ encoding: 'utf8',
17
+ stdio: 'pipe',
18
+ shell: true
19
+ }).trim();
20
+ const majorVersion = parseInt(npmVersion.split('.')[0]);
21
+ if (majorVersion >= 8) {
22
+ managers.push({ name: 'npm', value: 'npm', version: npmVersion });
23
+ }
24
+ } catch {}
25
+
26
+ // Check yarn (minimum version 1.22.0)
27
+ try {
28
+ const yarnVersion = execSync('yarn --version', {
29
+ encoding: 'utf8',
30
+ stdio: 'pipe',
31
+ shell: true
32
+ }).trim();
33
+ const [major, minor] = yarnVersion.split('.').map(Number);
34
+ if (major > 1 || (major === 1 && minor >= 22)) {
35
+ managers.push({ name: 'yarn', value: 'yarn', version: yarnVersion });
36
+ }
37
+ } catch {}
38
+
39
+ // Check pnpm (minimum version 7.0.0)
40
+ try {
41
+ const pnpmVersion = execSync('pnpm --version', {
42
+ encoding: 'utf8',
43
+ stdio: 'pipe',
44
+ shell: true
45
+ }).trim();
46
+ const majorVersion = parseInt(pnpmVersion.split('.')[0]);
47
+ if (majorVersion >= 7) {
48
+ managers.push({ name: 'pnpm', value: 'pnpm', version: pnpmVersion });
49
+ }
50
+ } catch {}
51
+
52
+ // Note: bun is not supported due to native binding compatibility issues
53
+
54
+ return managers;
55
+ }
56
+
57
+ async function setupProject(config, projectPath) {
58
+ const spinner = ora();
59
+
60
+ try {
61
+ // Download Nuxt template using giget (will create directory)
62
+ spinner.start(chalk.blue(`Downloading Nuxt template...`));
63
+ await downloadTemplate('github:enfyra/app', {
64
+ dir: projectPath,
65
+ force: true,
66
+ provider: 'github'
67
+ });
68
+ spinner.succeed(chalk.green('Template downloaded successfully'));
69
+
70
+ // Update package.json
71
+ spinner.start(chalk.blue('Updating package.json...'));
72
+ await updatePackageJson(projectPath, config);
73
+ spinner.succeed(chalk.green('Package.json updated'));
74
+
75
+
76
+ // Update Nuxt config with API URL
77
+ spinner.start(chalk.blue('Configuring Nuxt with API URL...'));
78
+ await updateNuxtConfig(projectPath, config);
79
+ spinner.succeed(chalk.green('Nuxt configuration updated'));
80
+
81
+ // Generate environment file
82
+ spinner.start(chalk.blue('Generating environment file...'));
83
+ await generateEnvFile(projectPath, config);
84
+ spinner.succeed(chalk.green('Environment file created'));
85
+
86
+ // Clean package manager restriction files
87
+ spinner.start(chalk.blue('Cleaning package manager restrictions...'));
88
+ await cleanPackageManagerRestrictions(projectPath);
89
+ spinner.succeed(chalk.green('Package manager restrictions cleaned'));
90
+
91
+ // Install dependencies
92
+ spinner.start(chalk.blue(`Installing dependencies with ${config.packageManager}...`));
93
+ await installDependencies(projectPath, config);
94
+ spinner.succeed(chalk.green('Dependencies installed successfully'));
95
+
96
+ // Initialize git repository
97
+ spinner.start(chalk.blue('Initializing git repository...'));
98
+ await initializeGit(projectPath);
99
+ spinner.succeed(chalk.green('Git repository initialized'));
100
+
101
+ } catch (error) {
102
+ spinner.fail(chalk.red('Setup failed'));
103
+
104
+ // Cleanup on failure
105
+ if (fs.existsSync(projectPath)) {
106
+ await fs.remove(projectPath);
107
+ }
108
+
109
+ throw error;
110
+ }
111
+ }
112
+
113
+
114
+
115
+ async function updatePackageJson(projectPath, config) {
116
+ const packageJsonPath = path.join(projectPath, 'package.json');
117
+
118
+ if (!fs.existsSync(packageJsonPath)) {
119
+ throw new Error('package.json not found in template');
120
+ }
121
+
122
+ const packageJson = await fs.readJson(packageJsonPath);
123
+
124
+ // Update project name
125
+ packageJson.name = config.projectName;
126
+
127
+ // Update version
128
+ packageJson.version = '0.1.0';
129
+
130
+ // Clear repository info
131
+ delete packageJson.repository;
132
+ delete packageJson.bugs;
133
+ delete packageJson.homepage;
134
+
135
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
136
+ }
137
+
138
+ async function cleanPackageManagerRestrictions(projectPath) {
139
+ // List of files that can restrict package manager usage
140
+ const restrictionFiles = [
141
+ '.npmrc',
142
+ '.yarnrc',
143
+ '.yarnrc.yml',
144
+ 'pnpm-workspace.yaml',
145
+ 'package-lock.json',
146
+ 'yarn.lock',
147
+ 'pnpm-lock.yaml',
148
+ 'bun.lockb'
149
+ ];
150
+
151
+ for (const file of restrictionFiles) {
152
+ const filePath = path.join(projectPath, file);
153
+ if (fs.existsSync(filePath)) {
154
+ await fs.remove(filePath);
155
+ console.log(chalk.yellow(`Removed ${file}`));
156
+ }
157
+ }
158
+
159
+ // Also check package.json for packageManager field and engines restrictions
160
+ const packageJsonPath = path.join(projectPath, 'package.json');
161
+ if (fs.existsSync(packageJsonPath)) {
162
+ const packageJson = await fs.readJson(packageJsonPath);
163
+
164
+ // Remove packageManager field that locks to specific manager
165
+ if (packageJson.packageManager) {
166
+ delete packageJson.packageManager;
167
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
168
+ console.log(chalk.yellow('Removed packageManager restriction from package.json'));
169
+ }
170
+ }
171
+ }
172
+
173
+
174
+ async function updateNuxtConfig(projectPath, config) {
175
+ const nuxtConfigPath = path.join(projectPath, 'nuxt.config.ts');
176
+
177
+ if (fs.existsSync(nuxtConfigPath)) {
178
+ let nuxtConfig = await fs.readFile(nuxtConfigPath, 'utf8');
179
+
180
+ // Update enfyraSDK apiUrl
181
+ if (nuxtConfig.includes('enfyraSDK:')) {
182
+ nuxtConfig = nuxtConfig.replace(
183
+ /enfyraSDK:\s*\{[^}]*\}/,
184
+ `enfyraSDK: {\n apiUrl: "${config.apiUrl}"\n }`
185
+ );
186
+ } else {
187
+ // Add enfyraSDK config
188
+ nuxtConfig = nuxtConfig.replace(
189
+ /}\);?\s*$/,
190
+ ` enfyraSDK: {\n apiUrl: "${config.apiUrl}"\n },\n});\n`
191
+ );
192
+ }
193
+
194
+
195
+ await fs.writeFile(nuxtConfigPath, nuxtConfig);
196
+ }
197
+ }
198
+
199
+ async function installDependencies(projectPath, config) {
200
+ const commands = {
201
+ npm: ['install', '--legacy-peer-deps'],
202
+ yarn: ['install'],
203
+ pnpm: ['install']
204
+ };
205
+
206
+ const args = commands[config.packageManager] || commands.npm;
207
+
208
+ return new Promise((resolve, reject) => {
209
+ const install = spawn(config.packageManager, args, {
210
+ cwd: projectPath,
211
+ stdio: 'pipe',
212
+ shell: true
213
+ });
214
+
215
+ let stdout = '';
216
+ let stderr = '';
217
+
218
+ install.stdout.on('data', (data) => {
219
+ stdout += data.toString();
220
+ });
221
+
222
+ install.stderr.on('data', (data) => {
223
+ stderr += data.toString();
224
+ });
225
+
226
+ install.on('close', (code) => {
227
+ if (code === 0) {
228
+ resolve();
229
+ } else {
230
+ const errorMsg = stderr || stdout || 'Unknown error';
231
+ reject(new Error(`Package installation failed with code ${code}: ${errorMsg}`));
232
+ }
233
+ });
234
+
235
+ install.on('error', (error) => {
236
+ reject(new Error(`Package manager spawn error: ${error.message}. Make sure ${config.packageManager} is installed and in PATH`));
237
+ });
238
+ });
239
+ }
240
+
241
+
242
+
243
+ async function initializeGit(projectPath) {
244
+ // Check if git is available
245
+ try {
246
+ execSync('git --version', { stdio: 'pipe', shell: true });
247
+ } catch {
248
+ // Git is not available, skip initialization
249
+ return;
250
+ }
251
+
252
+ return new Promise((resolve) => {
253
+ const gitInit = spawn('git', ['init'], {
254
+ cwd: projectPath,
255
+ stdio: 'pipe',
256
+ shell: true
257
+ });
258
+
259
+ gitInit.on('close', (code) => {
260
+ if (code === 0) {
261
+ // Add initial commit
262
+ const gitAdd = spawn('git', ['add', '.'], {
263
+ cwd: projectPath,
264
+ stdio: 'pipe',
265
+ shell: true
266
+ });
267
+
268
+ gitAdd.on('close', (addCode) => {
269
+ if (addCode === 0) {
270
+ const gitCommit = spawn('git', ['commit', '-m', 'Initial commit from create-app'], {
271
+ cwd: projectPath,
272
+ stdio: 'pipe',
273
+ shell: true
274
+ });
275
+
276
+ gitCommit.on('close', () => {
277
+ resolve();
278
+ });
279
+ } else {
280
+ resolve();
281
+ }
282
+ });
283
+ } else {
284
+ resolve();
285
+ }
286
+ });
287
+
288
+ gitInit.on('error', () => {
289
+ resolve();
290
+ });
291
+ });
292
+ }
293
+
294
+ module.exports = {
295
+ setupProject,
296
+ detectPackageManagers
297
+ };
@@ -0,0 +1,58 @@
1
+ const inquirer = require('inquirer');
2
+ const { validateProjectName, validatePort, validateApiUrl } = require('./validators');
3
+
4
+ function getPrompts(availableManagers) {
5
+ const questions = [
6
+ {
7
+ type: 'list',
8
+ name: 'packageManager',
9
+ message: 'Package manager:',
10
+ choices: availableManagers.map(pm => ({
11
+ name: `${getPackageManagerIcon(pm.name)} ${pm.name} (v${pm.version})`,
12
+ value: pm.value,
13
+ short: pm.name
14
+ })),
15
+ default: availableManagers.find(pm => pm.value === 'npm')?.value || availableManagers[0]?.value,
16
+ },
17
+ {
18
+ type: 'input',
19
+ name: 'apiUrl',
20
+ message: 'API base URL (must include http:// or https://):',
21
+ validate: validateApiUrl
22
+ },
23
+ {
24
+ type: 'input',
25
+ name: 'port',
26
+ message: 'App port:',
27
+ default: '3000',
28
+ validate: validatePort,
29
+ filter: (value) => parseInt(value, 10)
30
+ }
31
+ ];
32
+
33
+ return questions;
34
+ }
35
+
36
+ function getPackageManagerIcon(name) {
37
+ const icons = {
38
+ npm: 'šŸ“¦',
39
+ yarn: '🧶',
40
+ pnpm: '⚔',
41
+ bun: 'šŸš€'
42
+ };
43
+ return icons[name] || 'šŸ“¦';
44
+ }
45
+
46
+ async function promptForConfiguration(initialProjectName, availableManagers) {
47
+ const prompts = getPrompts(availableManagers);
48
+ const config = await inquirer.prompt(prompts);
49
+
50
+ // Add project name to config
51
+ config.projectName = initialProjectName;
52
+
53
+ return config;
54
+ }
55
+
56
+ module.exports = {
57
+ promptForConfiguration
58
+ };
@@ -0,0 +1,140 @@
1
+ const chalk = require('chalk');
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+
5
+ function checkNodeVersion() {
6
+ const currentVersion = process.version;
7
+ const requiredVersion = '20.0.0';
8
+
9
+ const current = parseVersion(currentVersion.slice(1)); // Remove 'v' prefix
10
+ const required = parseVersion(requiredVersion);
11
+
12
+ if (compareVersions(current, required) < 0) {
13
+ console.error(chalk.red.bold('āŒ Node.js version error'));
14
+ console.error(chalk.red(`Current version: ${currentVersion}`));
15
+ console.error(chalk.red(`Required version: >= v${requiredVersion}`));
16
+ console.error(chalk.yellow('Please update Node.js to continue.'));
17
+ process.exit(1);
18
+ }
19
+ }
20
+
21
+ function parseVersion(version) {
22
+ return version.split('.').map(Number);
23
+ }
24
+
25
+ function compareVersions(a, b) {
26
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
27
+ const aPart = a[i] || 0;
28
+ const bPart = b[i] || 0;
29
+
30
+ if (aPart > bPart) return 1;
31
+ if (aPart < bPart) return -1;
32
+ }
33
+ return 0;
34
+ }
35
+
36
+ function validateProjectName(name) {
37
+ if (!name || typeof name !== 'string') {
38
+ return 'Project name is required';
39
+ }
40
+
41
+ if (name.length < 1) {
42
+ return 'Project name cannot be empty';
43
+ }
44
+
45
+ if (name.length > 214) {
46
+ return 'Project name cannot exceed 214 characters';
47
+ }
48
+
49
+ if (!/^[a-z0-9-_]+$/i.test(name)) {
50
+ return 'Project name can only contain letters, numbers, hyphens, and underscores';
51
+ }
52
+
53
+ if (/^[.-]/.test(name)) {
54
+ return 'Project name cannot start with a dot or hyphen';
55
+ }
56
+
57
+ if (/[.-]$/.test(name)) {
58
+ return 'Project name cannot end with a dot or hyphen';
59
+ }
60
+
61
+ // Check for reserved names
62
+ const reservedNames = [
63
+ 'node_modules', '.git', '.env', 'package.json', 'dist', 'build',
64
+ 'src', 'public', 'assets', 'components', 'pages', 'layouts',
65
+ 'middleware', 'plugins', 'utils', 'server', 'static'
66
+ ];
67
+
68
+ if (reservedNames.includes(name.toLowerCase())) {
69
+ return `"${name}" is a reserved name and cannot be used`;
70
+ }
71
+
72
+ // Check if directory already exists
73
+ const projectPath = path.resolve(name);
74
+ if (fs.existsSync(projectPath)) {
75
+ return `Directory "${name}" already exists`;
76
+ }
77
+
78
+ return true;
79
+ }
80
+
81
+ function validatePort(port) {
82
+ const portNum = parseInt(port, 10);
83
+
84
+ if (isNaN(portNum)) {
85
+ return 'Port must be a number';
86
+ }
87
+
88
+ if (portNum < 1 || portNum > 65535) {
89
+ return 'Port must be between 1 and 65535';
90
+ }
91
+
92
+ return true;
93
+ }
94
+
95
+ function validateApiUrl(url) {
96
+ if (!url || url.trim().length === 0) {
97
+ return 'API URL is required';
98
+ }
99
+
100
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
101
+ return 'API URL must start with http:// or https:// (e.g., http://localhost:1105)';
102
+ }
103
+
104
+ try {
105
+ new URL(url);
106
+ return true;
107
+ } catch {
108
+ return 'Please enter a valid URL (e.g., http://localhost:1105)';
109
+ }
110
+ }
111
+
112
+ function validateNonEmpty(value, fieldName) {
113
+ if (!value || value.trim().length === 0) {
114
+ return `${fieldName} cannot be empty`;
115
+ }
116
+ return true;
117
+ }
118
+
119
+ function validatePositiveNumber(value, fieldName) {
120
+ const num = parseInt(value, 10);
121
+
122
+ if (isNaN(num)) {
123
+ return `${fieldName} must be a number`;
124
+ }
125
+
126
+ if (num < 1) {
127
+ return `${fieldName} must be a positive number`;
128
+ }
129
+
130
+ return true;
131
+ }
132
+
133
+ module.exports = {
134
+ checkNodeVersion,
135
+ validateProjectName,
136
+ validatePort,
137
+ validateApiUrl,
138
+ validateNonEmpty,
139
+ validatePositiveNumber
140
+ };
package/index.js ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Command } = require('commander');
4
+ const chalk = require('chalk');
5
+ const fs = require('fs-extra');
6
+ const path = require('path');
7
+ const inquirer = require('inquirer');
8
+ const { checkNodeVersion } = require('./components/validators');
9
+ const { promptForConfiguration } = require('./components/prompts');
10
+ const { setupProject, detectPackageManagers } = require('./components/project-setup');
11
+
12
+ const program = new Command();
13
+ const packageJson = require('./package.json');
14
+
15
+ // ASCII Art Banner
16
+ const banner = `
17
+ ${chalk.cyan.bold('╔═══════════════════════════════════════╗')}
18
+ ${chalk.cyan.bold('ā•‘')} ${chalk.white.bold('šŸš€ Create Enfyra App')} ${chalk.cyan.bold('ā•‘')}
19
+ ${chalk.cyan.bold('ā•‘')} ${chalk.gray('Frontend scaffolding made easy')} ${chalk.cyan.bold('ā•‘')}
20
+ ${chalk.cyan.bold('ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•')}
21
+ `;
22
+
23
+ async function main() {
24
+ console.log(banner);
25
+
26
+ try {
27
+ // Check Node.js version
28
+ checkNodeVersion();
29
+
30
+ // Detect available package managers
31
+ const availableManagers = detectPackageManagers();
32
+
33
+ if (availableManagers.length === 0) {
34
+ console.log(chalk.red('āŒ No compatible package managers found!'));
35
+ console.log(chalk.yellow('Please install npm (v8+), yarn (v1.22+), pnpm (v7+), or bun (v1+)'));
36
+ process.exit(1);
37
+ }
38
+
39
+ // Show detected package managers with versions
40
+ console.log(chalk.gray('Detected package managers:'));
41
+ availableManagers.forEach(pm => {
42
+ console.log(chalk.gray(` • ${pm.name} v${pm.version}`));
43
+ });
44
+ console.log('');
45
+
46
+ // Get project name from command line or prompt
47
+ let projectName = program.args[0];
48
+
49
+ if (!projectName) {
50
+ const { name } = await inquirer.prompt([
51
+ {
52
+ type: 'input',
53
+ name: 'name',
54
+ message: 'Project name:',
55
+ validate: (input) => {
56
+ if (!input || input.trim().length === 0) {
57
+ return 'Project name is required';
58
+ }
59
+ return true;
60
+ }
61
+ }
62
+ ]);
63
+ projectName = name;
64
+ }
65
+
66
+ // Validate project name and directory
67
+ const projectPath = path.resolve(projectName);
68
+
69
+ if (fs.existsSync(projectPath)) {
70
+ console.log(chalk.red(`āŒ Directory ${chalk.bold(projectName)} already exists!`));
71
+ process.exit(1);
72
+ }
73
+
74
+ // Prompt for configuration
75
+ const config = await promptForConfiguration(projectName, availableManagers);
76
+
77
+ // Setup project
78
+ await setupProject(config, projectPath);
79
+
80
+ // Success message
81
+ console.log(chalk.green.bold('\nšŸŽ‰ Project created successfully!'));
82
+ console.log(chalk.blue('\nšŸ“ Next steps:'));
83
+ console.log(chalk.gray(` cd ${projectName}`));
84
+ console.log(chalk.gray(` ${config.packageManager} run dev`));
85
+ console.log();
86
+
87
+ } catch (error) {
88
+ console.error(chalk.red.bold('\nāŒ Error creating project:'));
89
+ console.error(chalk.red(error.message));
90
+ console.error(chalk.gray(error.stack));
91
+
92
+ process.exit(1);
93
+ }
94
+ }
95
+
96
+ // Program setup
97
+ program
98
+ .name('create-app')
99
+ .description('Create a new Enfyra frontend application')
100
+ .version(packageJson.version)
101
+ .argument('[project-name]', 'Name of the project to create')
102
+ .action(main);
103
+
104
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@enfyra/create-app",
3
+ "version": "0.1.30",
4
+ "description": "Create Enfyra frontend applications with ease",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "create-app": "./index.js"
8
+ },
9
+ "preferGlobal": true,
10
+ "engines": {
11
+ "node": ">=20.0.0"
12
+ },
13
+ "scripts": {
14
+ "test": "echo \"Error: no test specified\" && exit 1"
15
+ },
16
+ "keywords": [
17
+ "enfyra",
18
+ "frontend",
19
+ "nuxt",
20
+ "vue",
21
+ "cli",
22
+ "scaffold",
23
+ "generator"
24
+ ],
25
+ "author": "Enfyra Team",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "chalk": "^4.1.2",
29
+ "commander": "^11.1.0",
30
+ "fs-extra": "^11.1.1",
31
+ "giget": "^2.0.0",
32
+ "inquirer": "^8.2.5",
33
+ "ora": "^5.4.1"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/dothinh115/create-enfyra-app.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/dothinh115/create-enfyra-app/issues"
41
+ },
42
+ "homepage": "https://github.com/dothinh115/create-enfyra-app#readme",
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }