metabinaries 1.0.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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/index.js +164 -0
- package/package.json +32 -0
- package/src/constants.js +62 -0
- package/src/templates/app.js +527 -0
- package/src/templates/configs.js +303 -0
- package/src/templates/core.js +328 -0
- package/src/templates/folder-structure.js +21 -0
- package/src/templates/layout.js +279 -0
- package/src/templates/misc.js +277 -0
- package/src/templates/packages.js +42 -0
- package/src/templates/ui-2.js +585 -0
- package/src/templates/ui-3.js +606 -0
- package/src/templates/ui-4.js +615 -0
- package/src/templates/ui.js +777 -0
- package/src/utils.js +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ahmed khairy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# MetaBinaries CLI
|
|
2
|
+
|
|
3
|
+
A powerful CLI tool to initialize advanced, enterprise-grade CRM projects using Next.js 15, Redux Toolkit, and a feature-based internal architecture.
|
|
4
|
+
|
|
5
|
+
## š Quick Start
|
|
6
|
+
|
|
7
|
+
You can use the CLI directly via `npx` without installation:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx metabinaries <project-name>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install it globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g metabinaries
|
|
17
|
+
metaBinaries <project-name>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## ⨠Features of Generated Projects
|
|
21
|
+
|
|
22
|
+
- **Next.js 15 (App Router)**: High-performance modern web architecture.
|
|
23
|
+
- **Feature-Based Architecture**: Business logic isolated in `lib/features/`.
|
|
24
|
+
- **Internationalization (i18n)**: Out-of-the-box support for English (LTR) and Arabic (RTL).
|
|
25
|
+
- **State Management**: Pre-configured Redux Toolkit.
|
|
26
|
+
- **Modern UI**: Tailwind CSS v4, Shadcn UI, and Framer Motion.
|
|
27
|
+
- **Form Validation**: Zod & React Hook Form.
|
|
28
|
+
- **Quality Tools**: Husky hooks and Conventional Commits configuration.
|
|
29
|
+
|
|
30
|
+
## š Generated Structure
|
|
31
|
+
|
|
32
|
+
The CLI generates a standardized folder structure including:
|
|
33
|
+
- `app/[locale]/`: Localized routes and layouts.
|
|
34
|
+
- `lib/features/`: Feature-specific logic (API, Services, Slices, Hooks).
|
|
35
|
+
- `components/ui/`: Reusable primitive components.
|
|
36
|
+
- `i18n/`: Advanced routing logic for multi-language support.
|
|
37
|
+
|
|
38
|
+
## š¤ Contributing
|
|
39
|
+
|
|
40
|
+
This CLI is developed and maintained by the **MetaBinaries Technical Team**.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
License: MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { folderStructure, getTemplateFiles, dependencies, devDependencies } from './src/constants.js';
|
|
7
|
+
import { runCommand } from './src/utils.js';
|
|
8
|
+
|
|
9
|
+
import chalk from 'chalk';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
let projectName = process.argv[2];
|
|
16
|
+
|
|
17
|
+
// Support "metaBinaries create [name]" or "metaBinaries create project [name]"
|
|
18
|
+
if (projectName === 'create') {
|
|
19
|
+
projectName = process.argv[3];
|
|
20
|
+
if (projectName === 'project') {
|
|
21
|
+
projectName = process.argv[4];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!projectName) {
|
|
26
|
+
console.error(chalk.red('ā Please provide a project name'));
|
|
27
|
+
console.log(chalk.cyan('Usage:'));
|
|
28
|
+
console.log(chalk.cyan(' npx metaBinaries <project-name>'));
|
|
29
|
+
console.log(chalk.cyan(' npx metaBinaries create <project-name>'));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Security: Validate project name to prevent command injection or path traversal
|
|
34
|
+
const safeProjectNameRegex = /^[a-zA-Z0-9-_]+$/;
|
|
35
|
+
if (!safeProjectNameRegex.test(projectName)) {
|
|
36
|
+
console.error(chalk.red('ā Invalid project name. Only alphanumeric characters, dashes, and underscores are allowed.'));
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ==================== MAIN FUNCTION ====================
|
|
41
|
+
async function createProject() {
|
|
42
|
+
const spinner = ora();
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
console.log(chalk.bold.blue(`\nš Creating MetaBinaries project: ${projectName}`));
|
|
46
|
+
console.log(chalk.bold.cyan(`⨠Developed by: MetaBinaries Technical Team\n`));
|
|
47
|
+
|
|
48
|
+
// Step 1: Initialize Next.js
|
|
49
|
+
console.log(chalk.yellow('š¦ Initializing Next.js... (Please answer the prompts below)'));
|
|
50
|
+
await runCommand('npx', [
|
|
51
|
+
'create-next-app@latest',
|
|
52
|
+
projectName,
|
|
53
|
+
'--skip-install',
|
|
54
|
+
'--skip-git'
|
|
55
|
+
]);
|
|
56
|
+
console.log(chalk.green('ā
Next.js initialized successfully!'));
|
|
57
|
+
|
|
58
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
59
|
+
process.chdir(projectPath);
|
|
60
|
+
|
|
61
|
+
// Step 2: Create folder structure
|
|
62
|
+
spinner.start(chalk.yellow('š Creating folder structure...'));
|
|
63
|
+
for (const folder of folderStructure) {
|
|
64
|
+
await fs.ensureDir(folder);
|
|
65
|
+
}
|
|
66
|
+
spinner.succeed(chalk.green('Folder structure created'));
|
|
67
|
+
|
|
68
|
+
// Step 3: Write template files
|
|
69
|
+
spinner.start(chalk.yellow('š Writing template files...'));
|
|
70
|
+
const templateFiles = getTemplateFiles(projectName);
|
|
71
|
+
for (const [filePath, content] of Object.entries(templateFiles)) {
|
|
72
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
73
|
+
await fs.writeFile(filePath, content);
|
|
74
|
+
}
|
|
75
|
+
spinner.succeed(chalk.green('Template files created'));
|
|
76
|
+
|
|
77
|
+
// Step 4: [Merged into Step 3]
|
|
78
|
+
spinner.succeed(chalk.green('Next.js configured via templates'));
|
|
79
|
+
|
|
80
|
+
// Step 5: Install dependencies
|
|
81
|
+
spinner.start(chalk.yellow('š Installing base dependencies...'));
|
|
82
|
+
await runCommand('npm', ['install']);
|
|
83
|
+
spinner.succeed(chalk.green('Base dependencies installed'));
|
|
84
|
+
|
|
85
|
+
spinner.start(chalk.yellow('š Installing additional libraries...'));
|
|
86
|
+
await runCommand('npm', ['install', ...dependencies]);
|
|
87
|
+
spinner.succeed(chalk.green('Additional dependencies installed'));
|
|
88
|
+
|
|
89
|
+
spinner.start(chalk.yellow('š Installing dev dependencies...'));
|
|
90
|
+
await runCommand('npm', ['install', '-D', ...devDependencies]);
|
|
91
|
+
spinner.succeed(chalk.green('Dev dependencies installed'));
|
|
92
|
+
|
|
93
|
+
// Step 6: Git will be initialized at the end after all files are written
|
|
94
|
+
|
|
95
|
+
// Step 7: Configure Husky & Scripts
|
|
96
|
+
spinner.start(chalk.yellow('š¶ Configuring Husky & Scripts...'));
|
|
97
|
+
try {
|
|
98
|
+
// Add scripts to package.json
|
|
99
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
100
|
+
const pkg = await fs.readJson(pkgPath);
|
|
101
|
+
pkg.scripts = {
|
|
102
|
+
...pkg.scripts,
|
|
103
|
+
"dev": "next dev",
|
|
104
|
+
"build": "npm run build:clean && npm run format && npm run build:next",
|
|
105
|
+
"build:clean": "rimraf .next && rimraf node_modules/.prisma",
|
|
106
|
+
"build:next": "next build --turbopack",
|
|
107
|
+
"build:production": "npm run build:clean && npm run format && npm run build:next",
|
|
108
|
+
"build:deploy": "npm run build:production",
|
|
109
|
+
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
110
|
+
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
111
|
+
"type-check": "tsc --noEmit",
|
|
112
|
+
"lint-staged": "lint-staged",
|
|
113
|
+
"prepare": "husky"
|
|
114
|
+
};
|
|
115
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
116
|
+
|
|
117
|
+
// Initialize Husky
|
|
118
|
+
await runCommand('npx', ['husky', 'init']);
|
|
119
|
+
|
|
120
|
+
// Overwrite husky hooks with our templates
|
|
121
|
+
for (const [filePath, content] of Object.entries(templateFiles)) {
|
|
122
|
+
if (filePath.startsWith('.husky/')) {
|
|
123
|
+
await fs.writeFile(filePath, content);
|
|
124
|
+
// Make hook executable on Unix-like systems
|
|
125
|
+
if (process.platform !== 'win32') {
|
|
126
|
+
await runCommand('chmod', ['+x', filePath]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
spinner.succeed(chalk.green('Husky configured'));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
spinner.warn(chalk.yellow('Husky configuration skipped or failed'));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Step 8: Initialize Git and make initial commit (after all files are written)
|
|
136
|
+
spinner.start(chalk.yellow('š§ Initializing Git...'));
|
|
137
|
+
try {
|
|
138
|
+
await runCommand('git', ['init']);
|
|
139
|
+
await runCommand('git', ['add', '.']);
|
|
140
|
+
await runCommand('git', ['commit', '-m', 'feat: initial commit from MetaBinaries']);
|
|
141
|
+
spinner.succeed(chalk.green('Git initialized with all files committed'));
|
|
142
|
+
} catch (e) {
|
|
143
|
+
spinner.warn(chalk.yellow('Git initialization skipped'));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Success message
|
|
147
|
+
console.log(chalk.bold.green('\nš Project created successfully!\n'));
|
|
148
|
+
console.log(chalk.white('š Next steps:'));
|
|
149
|
+
console.log(chalk.cyan(` cd ${projectName}`));
|
|
150
|
+
console.log(chalk.cyan(' npm run dev\n'));
|
|
151
|
+
console.log(chalk.white('š” Project includes:'));
|
|
152
|
+
console.log(chalk.gray(' ⢠Feature-based architecture'));
|
|
153
|
+
console.log(chalk.gray(' ⢠Redux Toolkit state management'));
|
|
154
|
+
console.log(chalk.gray(' ⢠Internationalization (en/ar)'));
|
|
155
|
+
console.log(chalk.gray(' ⢠Authentication structure'));
|
|
156
|
+
console.log(chalk.gray(' ⢠Shared components & utilities\n'));
|
|
157
|
+
|
|
158
|
+
} catch (error) {
|
|
159
|
+
spinner.fail(chalk.red(`Error: ${error.message}`));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
createProject();
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metabinaries",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MetaBinaries project initializer",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"metabinaries": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"src/",
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "node index.js test-project"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"nextjs",
|
|
20
|
+
"cli",
|
|
21
|
+
"template",
|
|
22
|
+
"boilerplate"
|
|
23
|
+
],
|
|
24
|
+
"author": "Your Name",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"chalk": "^5.6.2",
|
|
29
|
+
"fs-extra": "^11.3.3",
|
|
30
|
+
"ora": "^9.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Main constants file - aggregates all template modules
|
|
2
|
+
// =======================================================
|
|
3
|
+
|
|
4
|
+
// Import from separate template files
|
|
5
|
+
import { folderStructure } from './templates/folder-structure.js';
|
|
6
|
+
import { dependencies, devDependencies } from './templates/packages.js';
|
|
7
|
+
import { appTemplates } from './templates/app.js';
|
|
8
|
+
import { layoutTemplates } from './templates/layout.js';
|
|
9
|
+
import { coreTemplates } from './templates/core.js';
|
|
10
|
+
import { uiTemplates } from './templates/ui.js';
|
|
11
|
+
import { uiTemplates2 } from './templates/ui-2.js';
|
|
12
|
+
import { uiTemplates3 } from './templates/ui-3.js';
|
|
13
|
+
import { uiTemplates4 } from './templates/ui-4.js';
|
|
14
|
+
import { configTemplates } from './templates/configs.js';
|
|
15
|
+
import { miscTemplates } from './templates/misc.js';
|
|
16
|
+
|
|
17
|
+
// Re-export folderStructure
|
|
18
|
+
export { folderStructure };
|
|
19
|
+
|
|
20
|
+
// Re-export dependencies
|
|
21
|
+
export { dependencies, devDependencies };
|
|
22
|
+
|
|
23
|
+
// Helper function to resolve template values (handles both strings and functions)
|
|
24
|
+
const resolveTemplates = (templates, projectName) => {
|
|
25
|
+
const resolved = {};
|
|
26
|
+
for (const [key, value] of Object.entries(templates)) {
|
|
27
|
+
resolved[key] = typeof value === 'function' ? value(projectName) : value;
|
|
28
|
+
}
|
|
29
|
+
return resolved;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Combine all templates into a single getTemplateFiles function
|
|
33
|
+
export const getTemplateFiles = (projectName) => {
|
|
34
|
+
return {
|
|
35
|
+
// App Routes & Layouts
|
|
36
|
+
...resolveTemplates(appTemplates, projectName),
|
|
37
|
+
|
|
38
|
+
// Layout & Shared Components
|
|
39
|
+
...resolveTemplates(layoutTemplates, projectName),
|
|
40
|
+
|
|
41
|
+
// Core templates (lib, utils, i18n)
|
|
42
|
+
...resolveTemplates(coreTemplates, projectName),
|
|
43
|
+
|
|
44
|
+
// UI Components Part 1 (Alert, AnimatedGroup, Avatar, Badge, Breadcrumb, Button, Card)
|
|
45
|
+
...resolveTemplates(uiTemplates, projectName),
|
|
46
|
+
|
|
47
|
+
// UI Components Part 2 (Empty, InputGroup, Input, Label, NavigationMenu, Skeleton)
|
|
48
|
+
...resolveTemplates(uiTemplates2, projectName),
|
|
49
|
+
|
|
50
|
+
// UI Components Part 3 (Sonner, Stepper, Switch, Table, TextEffect, Textarea, Tooltip)
|
|
51
|
+
...resolveTemplates(uiTemplates3, projectName),
|
|
52
|
+
|
|
53
|
+
// UI Components Part 4 (Checkbox, Collapsible, Popover, ScrollArea, Separator)
|
|
54
|
+
...resolveTemplates(uiTemplates4, projectName),
|
|
55
|
+
|
|
56
|
+
// Configuration files
|
|
57
|
+
...resolveTemplates(configTemplates, projectName),
|
|
58
|
+
|
|
59
|
+
// Documentation and Husky hooks
|
|
60
|
+
...resolveTemplates(miscTemplates, projectName),
|
|
61
|
+
};
|
|
62
|
+
};
|