metabinaries 1.3.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.
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "metabinaries",
3
+ "version": "1.3.3",
4
+ "description": "šŸš€ Create a production-ready Next.js app in seconds",
5
+ "type": "module",
6
+ "bin": {
7
+ "metabinaries": "src/index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node src/index.js"
11
+ },
12
+ "keywords": [
13
+ "nextjs",
14
+ "next",
15
+ "react",
16
+ "cli",
17
+ "starter",
18
+ "template"
19
+ ],
20
+ "author": "Your Name",
21
+ "license": "MIT",
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ },
25
+ "dependencies": {
26
+ "@inquirer/prompts": "^7.2.0",
27
+ "axios": "^1.13.2",
28
+ "chalk": "^5.4.1",
29
+ "fs-extra": "^11.2.0",
30
+ "ora": "^8.1.1"
31
+ }
32
+ }
@@ -0,0 +1,94 @@
1
+ // Main constants file - aggregates all template modules
2
+ // =======================================================
3
+ // Clean version - Frontend only, no auth/backend dependencies
4
+
5
+ // Import from separate template files
6
+ import { getFolderStructure } from './templates/folder-structure.js';
7
+ import { dependencies, devDependencies } from './templates/packages.js';
8
+ import { appTemplates } from './templates/app-clean.js';
9
+ import { layoutTemplates } from './templates/layout-clean.js';
10
+ import { coreTemplates } from './templates/core-clean.js';
11
+ import { uiTemplates } from './templates/ui.js';
12
+ import { uiTemplates2 } from './templates/ui-2.js';
13
+ import { uiTemplates3 } from './templates/ui-3.js';
14
+ import { uiTemplates4 } from './templates/ui-4.js';
15
+ import { configTemplates } from './templates/configs.js';
16
+ import { miscTemplates } from './templates/misc.js';
17
+ import { aiChatTemplates } from './templates/feature-ai-chat.js';
18
+
19
+ // Re-export getFolderStructure
20
+ export { getFolderStructure };
21
+
22
+ // Re-export dependencies
23
+ export { dependencies, devDependencies };
24
+
25
+ // Helper function to resolve template values (handles both strings and functions)
26
+ const resolveTemplates = (templatesInput, projectName, options = {}) => {
27
+ // If the input is a function (like coreTemplates), execute it first to get the object
28
+ const templates =
29
+ typeof templatesInput === 'function'
30
+ ? templatesInput(projectName, options)
31
+ : templatesInput;
32
+
33
+ const resolved = {};
34
+ for (const [key, value] of Object.entries(templates)) {
35
+ resolved[key] =
36
+ typeof value === 'function' ? value(projectName, options) : value;
37
+ }
38
+ return resolved;
39
+ };
40
+
41
+ // Combine all templates into a single getTemplateFiles function
42
+ export const getTemplateFiles = (projectName, options = {}) => {
43
+ const { includeRedux = false, includeAIChat = false } = options;
44
+
45
+ const templates = {
46
+ // App Routes & Layouts
47
+ ...resolveTemplates(appTemplates, projectName, options),
48
+
49
+ // Layout & Shared Components
50
+ ...resolveTemplates(layoutTemplates, projectName, options),
51
+
52
+ // Core templates (lib, utils, i18n)
53
+ ...resolveTemplates(coreTemplates, projectName, options),
54
+
55
+ // UI Components Part 1 (Alert, AnimatedGroup, Avatar, Badge, Breadcrumb, Button, Card)
56
+ ...resolveTemplates(uiTemplates, projectName, options),
57
+
58
+ // UI Components Part 2 (Empty, InputGroup, Input, Label, NavigationMenu, Skeleton)
59
+ ...resolveTemplates(uiTemplates2, projectName, options),
60
+
61
+ // UI Components Part 3 (Sonner, Stepper, Switch, Table, TextEffect, Textarea, Tooltip)
62
+ ...resolveTemplates(uiTemplates3, projectName, options),
63
+
64
+ // UI Components Part 4 (Checkbox, Collapsible, Popover, ScrollArea, Separator)
65
+ ...resolveTemplates(uiTemplates4, projectName, options),
66
+
67
+ // Configuration files
68
+ ...resolveTemplates(configTemplates, projectName, options),
69
+
70
+ // Documentation and Husky hooks
71
+ ...resolveTemplates(miscTemplates, projectName, options),
72
+ };
73
+
74
+ // Handle AI Chat & Redux Templates
75
+ if (includeAIChat || includeRedux) {
76
+ const aiTemplates = resolveTemplates(aiChatTemplates, projectName, options);
77
+
78
+ if (includeAIChat) {
79
+ // Include everything
80
+ Object.assign(templates, aiTemplates);
81
+ } else if (includeRedux) {
82
+ // Only include store-related files if only Redux is selected
83
+ const storeTemplates = {};
84
+ for (const [key, value] of Object.entries(aiTemplates)) {
85
+ if (key.startsWith('store/') || key.startsWith('services/')) {
86
+ storeTemplates[key] = value;
87
+ }
88
+ }
89
+ Object.assign(templates, storeTemplates);
90
+ }
91
+ }
92
+
93
+ return templates;
94
+ };
package/src/index.js ADDED
@@ -0,0 +1,219 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { input, select, confirm } from '@inquirer/prompts';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import fs from 'fs-extra';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { getTemplateFiles, getFolderStructure, dependencies, devDependencies } from './constants.js';
10
+ import { runCommand } from './utils.js';
11
+
12
+ // Get __dirname equivalent in ESM
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ // CLI Banner
17
+ console.log(chalk.bold.cyan(`
18
+ ╔═══════════════════════════════════════════════════════════╗
19
+ ā•‘ ā•‘
20
+ ā•‘ šŸš€ Next.js Starter Kit Generator ā•‘
21
+ ā•‘ Create a production-ready Next.js app in seconds ā•‘
22
+ ā•‘ Developed by: Meta Binaries technical team ā•‘
23
+ ā•‘ ā•‘
24
+ ā•‘ ā•‘
25
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
26
+ `));
27
+
28
+ async function main() {
29
+ try {
30
+ // Step 1: Get project name from CLI argument or prompt
31
+ let projectName = process.argv[2];
32
+
33
+ if (projectName) {
34
+ // Validate project name from CLI argument
35
+ if (!/^[a-z0-9-]+$/.test(projectName)) {
36
+ console.log(chalk.red('\nāŒ Project name must contain only lowercase letters, numbers, and hyphens'));
37
+ process.exit(1);
38
+ }
39
+ } else {
40
+ // Ask for project name if not provided
41
+ projectName = await input({
42
+ message: 'What is your project name?',
43
+ default: 'my-nextjs-app',
44
+ validate: (value) => {
45
+ if (!value.trim()) return 'Project name is required';
46
+ if (!/^[a-z0-9-]+$/.test(value)) {
47
+ return 'Project name must contain only lowercase letters, numbers, and hyphens';
48
+ }
49
+ return true;
50
+ },
51
+ });
52
+ }
53
+
54
+ // Step 2: Select framework version
55
+ const framework = await select({
56
+ message: 'Which Next.js version would you like to use?',
57
+ choices: [
58
+ { name: 'Next.js 15 (Latest)', value: 'next15' },
59
+ { name: 'Next.js 14 (Stable)', value: 'next14' },
60
+ ],
61
+ });
62
+
63
+ // Step 3: Select styling approach
64
+ const styling = await select({
65
+ message: 'Choose your styling approach:',
66
+ choices: [
67
+ { name: 'Tailwind CSS v4 (Recommended)', value: 'tailwind-v4' },
68
+ { name: 'Tailwind CSS v3', value: 'tailwind-v3' },
69
+ { name: 'Plain CSS', value: 'plain-css' },
70
+ ],
71
+ });
72
+
73
+ // Step 4: Select i18n support
74
+ const i18n = await confirm({
75
+ message: 'Enable internationalization (i18n) support? (English + Arabic)',
76
+ default: true,
77
+ });
78
+
79
+ // Step 5: Select additional features
80
+ const includeRedux = await confirm({
81
+ message: 'Include Redux Toolkit for state management?',
82
+ default: false,
83
+ });
84
+
85
+ const includeAIChat = await confirm({
86
+ message: 'Include AI Chat feature?',
87
+ default: false,
88
+ });
89
+
90
+ // Step 6: Confirm installation
91
+ const shouldInstall = await confirm({
92
+ message: 'Install dependencies after setup?',
93
+ default: true,
94
+ });
95
+
96
+ // Create project directory
97
+ const projectPath = path.join(process.cwd(), projectName);
98
+
99
+ if (fs.existsSync(projectPath)) {
100
+ const overwrite = await confirm({
101
+ message: `Directory "${projectName}" already exists. Overwrite?`,
102
+ default: false,
103
+ });
104
+
105
+ if (!overwrite) {
106
+ console.log(chalk.yellow('\nāœ‹ Setup cancelled.'));
107
+ process.exit(0);
108
+ }
109
+
110
+ fs.removeSync(projectPath);
111
+ }
112
+
113
+ const spinner = ora('Creating project structure...').start();
114
+
115
+ // Create base folders
116
+ const structure = getFolderStructure({ includeRedux, includeAIChat });
117
+ structure.forEach((folder) => {
118
+ const folderPath = path.join(projectPath, folder);
119
+ fs.ensureDirSync(folderPath);
120
+ });
121
+
122
+ spinner.succeed('Project structure created!');
123
+
124
+ // Generate template files
125
+ spinner.start('Generating files...');
126
+ const templateFiles = getTemplateFiles(projectName, { includeRedux, includeAIChat });
127
+
128
+ for (const [filePath, content] of Object.entries(templateFiles)) {
129
+ const fullPath = path.join(projectPath, filePath);
130
+ fs.ensureDirSync(path.dirname(fullPath));
131
+ fs.writeFileSync(fullPath, content, 'utf-8');
132
+ }
133
+
134
+ spinner.succeed('Files generated!');
135
+
136
+ // Create package.json
137
+ spinner.start('Creating package.json...');
138
+ const packageJson = {
139
+ name: projectName,
140
+ version: '0.1.0',
141
+ private: true,
142
+ type: 'module',
143
+ scripts: {
144
+ dev: 'next dev',
145
+ build: 'next build',
146
+ start: 'next start',
147
+ lint: 'next lint',
148
+ prepare: 'husky',
149
+ },
150
+ dependencies: {
151
+ ...dependencies,
152
+ },
153
+ devDependencies: {
154
+ ...devDependencies,
155
+ },
156
+ };
157
+
158
+ // Adjust dependencies based on selections
159
+ if (framework === 'next14') {
160
+ packageJson.dependencies.next = '^14.2.0';
161
+ }
162
+
163
+ // Keep Redux if either Redux or AI Chat is selected
164
+ if (!includeRedux && !includeAIChat) {
165
+ delete packageJson.dependencies['@reduxjs/toolkit'];
166
+ delete packageJson.dependencies['react-redux'];
167
+ }
168
+
169
+ fs.writeJsonSync(
170
+ path.join(projectPath, 'package.json'),
171
+ packageJson,
172
+ { spaces: 2 }
173
+ );
174
+
175
+ spinner.succeed('package.json created!');
176
+
177
+ // Install dependencies
178
+ if (shouldInstall) {
179
+ spinner.start('Installing dependencies (this may take a few minutes)...');
180
+
181
+ try {
182
+ process.chdir(projectPath);
183
+ await runCommand('npm', ['install']);
184
+ spinner.succeed('Dependencies installed!');
185
+ } catch (error) {
186
+ spinner.fail('Failed to install dependencies');
187
+ console.log(chalk.yellow('\nāš ļø You can install them manually by running:'));
188
+ console.log(chalk.cyan(` cd ${projectName} && npm install\n`));
189
+ }
190
+ }
191
+
192
+ // Success message
193
+ console.log(chalk.green.bold('\nāœ… Project created successfully!\n'));
194
+ console.log(chalk.cyan('šŸ“ Project location:'), chalk.white(projectPath));
195
+ console.log(chalk.cyan('\nšŸš€ Get started:\n'));
196
+ console.log(chalk.white(` cd ${projectName}`));
197
+ if (!shouldInstall) {
198
+ console.log(chalk.white(' npm install'));
199
+ }
200
+ console.log(chalk.white(' npm run dev\n'));
201
+ console.log(chalk.gray('───────────────────────────────────────────────────────────'));
202
+ console.log(chalk.cyan('šŸ“– Next steps:'));
203
+ console.log(chalk.white(' • Edit app/[locale]/page.tsx to start building'));
204
+ console.log(chalk.white(' • Customize styles in app/[locale]/globals.css'));
205
+ console.log(chalk.white(' • Add components in components/'));
206
+ console.log(chalk.gray('───────────────────────────────────────────────────────────\n'));
207
+
208
+ } catch (error) {
209
+ if (error.name === 'ExitPromptError') {
210
+ console.log(chalk.yellow('\nāœ‹ Setup cancelled.'));
211
+ process.exit(0);
212
+ }
213
+
214
+ console.error(chalk.red('\nāŒ Error:'), error.message);
215
+ process.exit(1);
216
+ }
217
+ }
218
+
219
+ main();