create-project-cli-cm 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/NPM_PUBLISH_GUIDE.md +155 -0
- package/README.md +124 -0
- package/SUBMISSION.md +194 -0
- package/index.js +176 -0
- package/package.json +38 -0
- package/screenShot_collection.pdf +0 -0
- package/test.js +208 -0
- package/utils/argumentParser.js +61 -0
- package/utils/logger.js +43 -0
- package/utils/templateGenerator.js +1707 -0
package/test.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Suite for create-project-cli
|
|
3
|
+
* Run this to verify all functionality works correctly
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
|
|
10
|
+
class TestRunner {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.testsPassed = 0;
|
|
13
|
+
this.testsFailed = 0;
|
|
14
|
+
this.testResults = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Run a test and track results
|
|
19
|
+
*/
|
|
20
|
+
runTest(name, testFn) {
|
|
21
|
+
try {
|
|
22
|
+
console.log(`\n๐งช Testing: ${name}...`);
|
|
23
|
+
testFn();
|
|
24
|
+
this.testsPassed++;
|
|
25
|
+
this.testResults.push({ name, status: 'PASS' });
|
|
26
|
+
console.log(`โ ${name} - PASSED`);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
this.testsFailed++;
|
|
29
|
+
this.testResults.push({ name, status: 'FAIL', error: error.message });
|
|
30
|
+
console.error(`โ ${name} - FAILED: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Clean up test directories
|
|
36
|
+
*/
|
|
37
|
+
cleanup() {
|
|
38
|
+
const testDirs = ['test-basic-app', 'test-web-app', 'test-api-app', 'test-cli-app'];
|
|
39
|
+
testDirs.forEach(dir => {
|
|
40
|
+
const dirPath = path.join(process.cwd(), dir);
|
|
41
|
+
if (fs.existsSync(dirPath)) {
|
|
42
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Assert that a condition is true
|
|
49
|
+
*/
|
|
50
|
+
assert(condition, message) {
|
|
51
|
+
if (!condition) {
|
|
52
|
+
throw new Error(message || 'Assertion failed');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Test: Basic template creation
|
|
58
|
+
*/
|
|
59
|
+
testBasicTemplate() {
|
|
60
|
+
execSync('node index.js test-basic-app --template basic', { stdio: 'ignore' });
|
|
61
|
+
|
|
62
|
+
const projectPath = path.join(process.cwd(), 'test-basic-app');
|
|
63
|
+
this.assert(fs.existsSync(projectPath), 'Project directory should exist');
|
|
64
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src')), 'src directory should exist');
|
|
65
|
+
this.assert(fs.existsSync(path.join(projectPath, 'utils')), 'utils directory should exist');
|
|
66
|
+
this.assert(fs.existsSync(path.join(projectPath, 'package.json')), 'package.json should exist');
|
|
67
|
+
this.assert(fs.existsSync(path.join(projectPath, 'README.md')), 'README.md should exist');
|
|
68
|
+
|
|
69
|
+
// Cleanup
|
|
70
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Test: Web template creation
|
|
75
|
+
*/
|
|
76
|
+
testWebTemplate() {
|
|
77
|
+
execSync('node index.js test-web-app -t web', { stdio: 'ignore' });
|
|
78
|
+
|
|
79
|
+
const projectPath = path.join(process.cwd(), 'test-web-app');
|
|
80
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'index.html')), 'index.html should exist');
|
|
81
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'css', 'style.css')), 'style.css should exist');
|
|
82
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'js', 'app.js')), 'app.js should exist');
|
|
83
|
+
|
|
84
|
+
// Cleanup
|
|
85
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Test: API template creation
|
|
90
|
+
*/
|
|
91
|
+
testApiTemplate() {
|
|
92
|
+
execSync('node index.js test-api-app -t api', { stdio: 'ignore' });
|
|
93
|
+
|
|
94
|
+
const projectPath = path.join(process.cwd(), 'test-api-app');
|
|
95
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'server.js')), 'server.js should exist');
|
|
96
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'routes')), 'routes directory should exist');
|
|
97
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'controllers')), 'controllers directory should exist');
|
|
98
|
+
this.assert(fs.existsSync(path.join(projectPath, 'config')), 'config directory should exist');
|
|
99
|
+
|
|
100
|
+
// Cleanup
|
|
101
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Test: CLI template creation
|
|
106
|
+
*/
|
|
107
|
+
testCliTemplate() {
|
|
108
|
+
execSync('node index.js test-cli-app -t cli', { stdio: 'ignore' });
|
|
109
|
+
|
|
110
|
+
const projectPath = path.join(process.cwd(), 'test-cli-app');
|
|
111
|
+
this.assert(fs.existsSync(path.join(projectPath, 'src', 'cli.js')), 'cli.js should exist');
|
|
112
|
+
this.assert(fs.existsSync(path.join(projectPath, 'commands')), 'commands directory should exist');
|
|
113
|
+
|
|
114
|
+
// Cleanup
|
|
115
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Test: Invalid project name handling
|
|
120
|
+
*/
|
|
121
|
+
testInvalidProjectName() {
|
|
122
|
+
try {
|
|
123
|
+
execSync('node index.js "test@invalid#name" --template basic', { stdio: 'ignore' });
|
|
124
|
+
throw new Error('Should have failed with invalid project name');
|
|
125
|
+
} catch (error) {
|
|
126
|
+
// Expected to fail
|
|
127
|
+
this.assert(error.status !== 0, 'Should exit with non-zero status for invalid name');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Test: Duplicate project name handling
|
|
133
|
+
*/
|
|
134
|
+
testDuplicateProjectName() {
|
|
135
|
+
execSync('node index.js test-duplicate-app --template basic', { stdio: 'ignore' });
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
execSync('node index.js test-duplicate-app --template basic', { stdio: 'ignore' });
|
|
139
|
+
throw new Error('Should have failed with duplicate project name');
|
|
140
|
+
} catch (error) {
|
|
141
|
+
// Expected to fail
|
|
142
|
+
this.assert(error.status !== 0, 'Should exit with non-zero status for duplicate name');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Cleanup
|
|
146
|
+
const projectPath = path.join(process.cwd(), 'test-duplicate-app');
|
|
147
|
+
if (fs.existsSync(projectPath)) {
|
|
148
|
+
fs.rmSync(projectPath, { recursive: true, force: true });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Test: Help command
|
|
154
|
+
*/
|
|
155
|
+
testHelpCommand() {
|
|
156
|
+
const output = execSync('node index.js --help').toString();
|
|
157
|
+
this.assert(output.includes('USAGE'), 'Help should contain USAGE section');
|
|
158
|
+
this.assert(output.includes('OPTIONS'), 'Help should contain OPTIONS section');
|
|
159
|
+
this.assert(output.includes('EXAMPLES'), 'Help should contain EXAMPLES section');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Run all tests
|
|
164
|
+
*/
|
|
165
|
+
runAll() {
|
|
166
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
167
|
+
console.log('โ CREATE-PROJECT-CLI - Test Suite โ');
|
|
168
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n');
|
|
169
|
+
|
|
170
|
+
// Cleanup before tests
|
|
171
|
+
this.cleanup();
|
|
172
|
+
|
|
173
|
+
// Run tests
|
|
174
|
+
this.runTest('Basic Template Creation', () => this.testBasicTemplate());
|
|
175
|
+
this.runTest('Web Template Creation', () => this.testWebTemplate());
|
|
176
|
+
this.runTest('API Template Creation', () => this.testApiTemplate());
|
|
177
|
+
this.runTest('CLI Template Creation', () => this.testCliTemplate());
|
|
178
|
+
this.runTest('Invalid Project Name Handling', () => this.testInvalidProjectName());
|
|
179
|
+
this.runTest('Duplicate Project Name Handling', () => this.testDuplicateProjectName());
|
|
180
|
+
this.runTest('Help Command', () => this.testHelpCommand());
|
|
181
|
+
|
|
182
|
+
// Final cleanup
|
|
183
|
+
this.cleanup();
|
|
184
|
+
|
|
185
|
+
// Display results
|
|
186
|
+
console.log('\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
|
|
187
|
+
console.log('โ Test Results โ');
|
|
188
|
+
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n');
|
|
189
|
+
|
|
190
|
+
this.testResults.forEach(result => {
|
|
191
|
+
const status = result.status === 'PASS' ? 'โ' : 'โ';
|
|
192
|
+
console.log(`${status} ${result.name}: ${result.status}`);
|
|
193
|
+
if (result.error) {
|
|
194
|
+
console.log(` Error: ${result.error}`);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
console.log(`\n๐ Summary: ${this.testsPassed} passed, ${this.testsFailed} failed\n`);
|
|
199
|
+
|
|
200
|
+
if (this.testsFailed > 0) {
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Run tests
|
|
207
|
+
const runner = new TestRunner();
|
|
208
|
+
runner.runAll();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArgumentParser
|
|
3
|
+
* Parses command-line arguments and extracts configuration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class ArgumentParser {
|
|
7
|
+
/**
|
|
8
|
+
* Parses command-line arguments into a configuration object
|
|
9
|
+
* @param {Array} args - Command-line arguments
|
|
10
|
+
* @returns {Object} Configuration object
|
|
11
|
+
*/
|
|
12
|
+
parse(args) {
|
|
13
|
+
const config = {
|
|
14
|
+
projectName: '',
|
|
15
|
+
template: 'basic',
|
|
16
|
+
gitInit: false,
|
|
17
|
+
author: ''
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// First non-flag argument is the project name
|
|
21
|
+
config.projectName = args.find(arg => !arg.startsWith('-'));
|
|
22
|
+
|
|
23
|
+
if (!config.projectName) {
|
|
24
|
+
throw new Error('Project name is required. Usage: create-proj <project-name> [options]');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Parse flags
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
const arg = args[i];
|
|
30
|
+
|
|
31
|
+
switch (arg) {
|
|
32
|
+
case '--template':
|
|
33
|
+
case '-t':
|
|
34
|
+
if (!args[i + 1] || args[i + 1].startsWith('-')) {
|
|
35
|
+
throw new Error('--template flag requires a value');
|
|
36
|
+
}
|
|
37
|
+
config.template = args[i + 1].toLowerCase();
|
|
38
|
+
i++; // Skip next argument as it's the value
|
|
39
|
+
break;
|
|
40
|
+
|
|
41
|
+
case '--git':
|
|
42
|
+
case '-g':
|
|
43
|
+
config.gitInit = true;
|
|
44
|
+
break;
|
|
45
|
+
|
|
46
|
+
case '--author':
|
|
47
|
+
case '-a':
|
|
48
|
+
if (!args[i + 1] || args[i + 1].startsWith('-')) {
|
|
49
|
+
throw new Error('--author flag requires a value');
|
|
50
|
+
}
|
|
51
|
+
config.author = args[i + 1];
|
|
52
|
+
i++; // Skip next argument as it's the value
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return config;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = ArgumentParser;
|
package/utils/logger.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger
|
|
3
|
+
* Provides colored console output for better user experience
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class Logger {
|
|
7
|
+
/**
|
|
8
|
+
* Log informational messages (blue)
|
|
9
|
+
*/
|
|
10
|
+
info(message) {
|
|
11
|
+
console.log(`\x1b[36m${message}\x1b[0m`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Log success messages (green)
|
|
16
|
+
*/
|
|
17
|
+
success(message) {
|
|
18
|
+
console.log(`\x1b[32m${message}\x1b[0m`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Log error messages (red)
|
|
23
|
+
*/
|
|
24
|
+
error(message) {
|
|
25
|
+
console.error(`\x1b[31m${message}\x1b[0m`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Log warning messages (yellow)
|
|
30
|
+
*/
|
|
31
|
+
warning(message) {
|
|
32
|
+
console.log(`\x1b[33m${message}\x1b[0m`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Log plain messages (no color)
|
|
37
|
+
*/
|
|
38
|
+
log(message) {
|
|
39
|
+
console.log(message);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = Logger;
|