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 +32 -0
- package/src/constants.js +94 -0
- package/src/index.js +219 -0
- package/src/templates/app-clean.js +1066 -0
- package/src/templates/configs.js +391 -0
- package/src/templates/core-clean.js +269 -0
- package/src/templates/feature-ai-chat.js +1786 -0
- package/src/templates/folder-structure.js +29 -0
- package/src/templates/layout-clean.js +788 -0
- package/src/templates/misc.js +275 -0
- package/src/templates/packages.js +74 -0
- package/src/templates/ui-2.js +585 -0
- package/src/templates/ui-3.js +606 -0
- package/src/templates/ui-4.js +1025 -0
- package/src/templates/ui.js +777 -0
- package/src/utils.js +38 -0
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
|
+
}
|
package/src/constants.js
ADDED
|
@@ -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();
|