@sachin-thakur/create-nodejs-app 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.
@@ -0,0 +1,99 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ async function generateGitHubActions(projectPath, config) {
5
+ const isTypeScript = config.language === 'typescript';
6
+
7
+ const workflow = `name: CI/CD Pipeline
8
+
9
+ on:
10
+ push:
11
+ branches: [ main, develop ]
12
+ pull_request:
13
+ branches: [ main, develop ]
14
+
15
+ jobs:
16
+ test:
17
+ runs-on: ubuntu-latest
18
+
19
+ strategy:
20
+ matrix:
21
+ node-version: [16.x, 18.x, 20.x]
22
+
23
+ steps:
24
+ - uses: actions/checkout@v3
25
+
26
+ - name: Use Node.js \${{ matrix.node-version }}
27
+ uses: actions/setup-node@v3
28
+ with:
29
+ node-version: \${{ matrix.node-version }}
30
+ cache: 'npm'
31
+
32
+ - name: Install dependencies
33
+ run: npm ci
34
+
35
+ - name: Run linter
36
+ run: npm run lint
37
+
38
+ ${isTypeScript ? `- name: Build TypeScript
39
+ run: npm run build
40
+
41
+ ` : ''}${config.testing !== 'none' ? `- name: Run tests
42
+ run: npm test
43
+
44
+ - name: Generate coverage report
45
+ run: npm run test:coverage
46
+
47
+ - name: Upload coverage to Codecov
48
+ uses: codecov/codecov-action@v3
49
+ with:
50
+ files: ./coverage/lcov.info
51
+ flags: unittests
52
+ name: codecov-umbrella
53
+
54
+ ` : ''}
55
+ build:
56
+ runs-on: ubuntu-latest
57
+ needs: test
58
+ if: github.ref == 'refs/heads/main'
59
+
60
+ steps:
61
+ - uses: actions/checkout@v3
62
+
63
+ - name: Set up Docker Buildx
64
+ uses: docker/setup-buildx-action@v2
65
+
66
+ - name: Login to DockerHub
67
+ uses: docker/login-action@v2
68
+ with:
69
+ username: \${{ secrets.DOCKERHUB_USERNAME }}
70
+ password: \${{ secrets.DOCKERHUB_TOKEN }}
71
+
72
+ - name: Build and push Docker image
73
+ uses: docker/build-push-action@v4
74
+ with:
75
+ context: .
76
+ push: true
77
+ tags: \${{ secrets.DOCKERHUB_USERNAME }}/\${{ github.event.repository.name }}:latest
78
+ cache-from: type=registry,ref=\${{ secrets.DOCKERHUB_USERNAME }}/\${{ github.event.repository.name }}:buildcache
79
+ cache-to: type=registry,ref=\${{ secrets.DOCKERHUB_USERNAME }}/\${{ github.event.repository.name }}:buildcache,mode=max
80
+
81
+ deploy:
82
+ runs-on: ubuntu-latest
83
+ needs: build
84
+ if: github.ref == 'refs/heads/main'
85
+
86
+ steps:
87
+ - name: Deploy to production
88
+ run: |
89
+ echo "Add your deployment commands here"
90
+ # Example: SSH into server and pull new image
91
+ # ssh user@server 'docker pull image && docker-compose up -d'
92
+ `;
93
+
94
+ const workflowDir = path.join(projectPath, '.github', 'workflows');
95
+ await fs.ensureDir(workflowDir);
96
+ await fs.writeFile(path.join(workflowDir, 'ci-cd.yml'), workflow);
97
+ }
98
+
99
+ module.exports = { generateGitHubActions };
@@ -0,0 +1,157 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+
4
+ async function generateDockerFiles(projectPath, config) {
5
+ const isTypeScript = config.language === 'typescript';
6
+
7
+ // Dockerfile
8
+ const dockerfile = `FROM node:18-alpine
9
+
10
+ WORKDIR /app
11
+
12
+ # Copy package files
13
+ COPY package*.json ./
14
+
15
+ # Install dependencies
16
+ RUN npm ci --only=production
17
+
18
+ # Copy source code
19
+ COPY . .
20
+
21
+ ${isTypeScript ? '# Build TypeScript\nRUN npm run build\n' : ''}
22
+ # Expose port
23
+ EXPOSE 3000
24
+
25
+ # Start application
26
+ CMD ["npm", "start"]
27
+ `;
28
+
29
+ await fs.writeFile(path.join(projectPath, 'Dockerfile'), dockerfile);
30
+
31
+ // .dockerignore
32
+ const dockerignore = `node_modules
33
+ npm-debug.log
34
+ .env
35
+ .env.local
36
+ .git
37
+ .gitignore
38
+ README.md
39
+ .vscode
40
+ .idea
41
+ *.log
42
+ coverage
43
+ .DS_Store
44
+ dist
45
+ build
46
+ `;
47
+
48
+ await fs.writeFile(path.join(projectPath, '.dockerignore'), dockerignore);
49
+
50
+ // docker-compose.yml
51
+ let dockerCompose = `version: '3.8'
52
+
53
+ services:
54
+ app:
55
+ build: .
56
+ ports:
57
+ - "3000:3000"
58
+ environment:
59
+ - NODE_ENV=development
60
+ volumes:
61
+ - .:/app
62
+ - /app/node_modules
63
+ depends_on:
64
+ `;
65
+
66
+ if (config.database === 'postgresql') {
67
+ dockerCompose += ` - postgres
68
+ networks:
69
+ - app-network
70
+
71
+ postgres:
72
+ image: postgres:15-alpine
73
+ environment:
74
+ POSTGRES_USER: postgres
75
+ POSTGRES_PASSWORD: password
76
+ POSTGRES_DB: myapp_db
77
+ ports:
78
+ - "5432:5432"
79
+ volumes:
80
+ - postgres-data:/var/lib/postgresql/data
81
+ networks:
82
+ - app-network
83
+ `;
84
+ } else if (config.database === 'mongodb') {
85
+ dockerCompose += ` - mongodb
86
+ networks:
87
+ - app-network
88
+
89
+ mongodb:
90
+ image: mongo:7
91
+ ports:
92
+ - "27017:27017"
93
+ environment:
94
+ MONGO_INITDB_ROOT_USERNAME: root
95
+ MONGO_INITDB_ROOT_PASSWORD: password
96
+ MONGO_INITDB_DATABASE: myapp_db
97
+ volumes:
98
+ - mongodb-data:/data/db
99
+ networks:
100
+ - app-network
101
+ `;
102
+ } else if (config.database === 'mysql') {
103
+ dockerCompose += ` - mysql
104
+ networks:
105
+ - app-network
106
+
107
+ mysql:
108
+ image: mysql:8
109
+ environment:
110
+ MYSQL_ROOT_PASSWORD: password
111
+ MYSQL_DATABASE: myapp_db
112
+ ports:
113
+ - "3306:3306"
114
+ volumes:
115
+ - mysql-data:/var/lib/mysql
116
+ networks:
117
+ - app-network
118
+ `;
119
+ }
120
+
121
+ if (config.features.includes('cache') || config.features.includes('jobs')) {
122
+ dockerCompose += `
123
+ redis:
124
+ image: redis:7-alpine
125
+ ports:
126
+ - "6379:6379"
127
+ volumes:
128
+ - redis-data:/data
129
+ networks:
130
+ - app-network
131
+ `;
132
+ }
133
+
134
+ dockerCompose += `
135
+ networks:
136
+ app-network:
137
+ driver: bridge
138
+
139
+ volumes:
140
+ `;
141
+
142
+ if (config.database === 'postgresql') {
143
+ dockerCompose += ` postgres-data:\n`;
144
+ } else if (config.database === 'mongodb') {
145
+ dockerCompose += ` mongodb-data:\n`;
146
+ } else if (config.database === 'mysql') {
147
+ dockerCompose += ` mysql-data:\n`;
148
+ }
149
+
150
+ if (config.features.includes('cache') || config.features.includes('jobs')) {
151
+ dockerCompose += ` redis-data:\n`;
152
+ }
153
+
154
+ await fs.writeFile(path.join(projectPath, 'docker-compose.yml'), dockerCompose);
155
+ }
156
+
157
+ module.exports = { generateDockerFiles };
@@ -0,0 +1,102 @@
1
+ function generateEnvFile(config) {
2
+ let envContent = `# Server Configuration
3
+ NODE_ENV=development
4
+ PORT=3000
5
+ HOST=localhost
6
+
7
+ # Application
8
+ APP_NAME=${config.projectName || 'My App'}
9
+ APP_URL=http://localhost:3000
10
+
11
+ `;
12
+
13
+ // Database configuration
14
+ if (config.database === 'postgresql') {
15
+ envContent += `# PostgreSQL Database
16
+ DB_HOST=localhost
17
+ DB_PORT=5432
18
+ DB_NAME=myapp_db
19
+ DB_USER=postgres
20
+ DB_PASSWORD=password
21
+ DATABASE_URL=postgresql://postgres:password@localhost:5432/myapp_db
22
+
23
+ `;
24
+ } else if (config.database === 'mongodb') {
25
+ envContent += `# MongoDB Database
26
+ MONGODB_URI=mongodb://localhost:27017/myapp_db
27
+
28
+ `;
29
+ } else if (config.database === 'mysql') {
30
+ envContent += `# MySQL Database
31
+ DB_HOST=localhost
32
+ DB_PORT=3306
33
+ DB_NAME=myapp_db
34
+ DB_USER=root
35
+ DB_PASSWORD=password
36
+
37
+ `;
38
+ }
39
+
40
+ // JWT configuration
41
+ if (config.features.includes('auth')) {
42
+ envContent += `# Authentication
43
+ JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
44
+ JWT_EXPIRES_IN=7d
45
+ REFRESH_TOKEN_SECRET=your-refresh-token-secret
46
+ REFRESH_TOKEN_EXPIRES_IN=30d
47
+
48
+ `;
49
+ }
50
+
51
+ // Redis configuration
52
+ if (config.features.includes('cache') || config.features.includes('jobs')) {
53
+ envContent += `# Redis Configuration
54
+ REDIS_HOST=localhost
55
+ REDIS_PORT=6379
56
+ REDIS_PASSWORD=
57
+
58
+ `;
59
+ }
60
+
61
+ // Email configuration
62
+ if (config.features.includes('email')) {
63
+ envContent += `# Email Configuration
64
+ SMTP_HOST=smtp.gmail.com
65
+ SMTP_PORT=587
66
+ SMTP_USER=your-email@gmail.com
67
+ SMTP_PASSWORD=your-app-password
68
+ EMAIL_FROM=noreply@yourapp.com
69
+
70
+ `;
71
+ }
72
+
73
+ // CORS configuration
74
+ if (config.features.includes('cors')) {
75
+ envContent += `# CORS Configuration
76
+ CORS_ORIGIN=http://localhost:3000
77
+
78
+ `;
79
+ }
80
+
81
+ // Rate limiting
82
+ if (config.features.includes('rate-limit')) {
83
+ envContent += `# Rate Limiting
84
+ RATE_LIMIT_WINDOW_MS=900000
85
+ RATE_LIMIT_MAX_REQUESTS=100
86
+
87
+ `;
88
+ }
89
+
90
+ // Logging
91
+ if (config.features.includes('logging')) {
92
+ envContent += `# Logging
93
+ LOG_LEVEL=info
94
+ LOG_FILE=logs/app.log
95
+
96
+ `;
97
+ }
98
+
99
+ return envContent.trim() + '\n';
100
+ }
101
+
102
+ module.exports = { generateEnvFile };
@@ -0,0 +1,142 @@
1
+ function generatePackageJson(projectName, config) {
2
+ const isTypeScript = config.language === 'typescript';
3
+ const dependencies = {
4
+ express: '^4.18.2',
5
+ dotenv: '^16.3.1',
6
+ cors: '^2.8.5',
7
+ };
8
+
9
+ const devDependencies = {
10
+ nodemon: '^3.0.2',
11
+ eslint: '^8.55.0',
12
+ prettier: '^3.1.1',
13
+ };
14
+
15
+ // TypeScript dependencies
16
+ if (isTypeScript) {
17
+ devDependencies['typescript'] = '^5.3.3';
18
+ devDependencies['@types/node'] = '^20.10.6';
19
+ devDependencies['@types/express'] = '^4.17.21';
20
+ devDependencies['@typescript-eslint/eslint-plugin'] = '^6.16.0';
21
+ devDependencies['@typescript-eslint/parser'] = '^6.16.0';
22
+ devDependencies['ts-node'] = '^10.9.2';
23
+ devDependencies['ts-node-dev'] = '^2.0.0';
24
+ }
25
+
26
+ // Database dependencies
27
+ if (config.database === 'postgresql') {
28
+ dependencies['pg'] = '^8.11.3';
29
+ dependencies['pg-hstore'] = '^2.3.4';
30
+ if (isTypeScript) devDependencies['@types/pg'] = '^8.10.9';
31
+ } else if (config.database === 'mongodb') {
32
+ dependencies['mongoose'] = '^8.0.3';
33
+ } else if (config.database === 'mysql') {
34
+ dependencies['mysql2'] = '^3.7.0';
35
+ }
36
+
37
+ // Feature dependencies
38
+ if (config.features.includes('auth')) {
39
+ dependencies['jsonwebtoken'] = '^9.0.2';
40
+ dependencies['bcryptjs'] = '^2.4.3';
41
+ if (isTypeScript) {
42
+ devDependencies['@types/jsonwebtoken'] = '^9.0.5';
43
+ devDependencies['@types/bcryptjs'] = '^2.4.6';
44
+ }
45
+ }
46
+
47
+ if (config.features.includes('validation')) {
48
+ dependencies['zod'] = '^3.22.4';
49
+ }
50
+
51
+ if (config.features.includes('logging')) {
52
+ dependencies['winston'] = '^3.11.0';
53
+ dependencies['morgan'] = '^1.10.0';
54
+ if (isTypeScript) devDependencies['@types/morgan'] = '^1.9.9';
55
+ }
56
+
57
+ if (config.features.includes('swagger')) {
58
+ dependencies['swagger-ui-express'] = '^5.0.0';
59
+ dependencies['swagger-jsdoc'] = '^6.2.8';
60
+ if (isTypeScript) {
61
+ devDependencies['@types/swagger-ui-express'] = '^4.1.6';
62
+ devDependencies['@types/swagger-jsdoc'] = '^6.0.4';
63
+ }
64
+ }
65
+
66
+ if (config.features.includes('rate-limit')) {
67
+ dependencies['express-rate-limit'] = '^7.1.5';
68
+ }
69
+
70
+ if (config.features.includes('file-upload')) {
71
+ dependencies['multer'] = '^1.4.5-lts.1';
72
+ if (isTypeScript) devDependencies['@types/multer'] = '^1.4.11';
73
+ }
74
+
75
+ if (config.features.includes('email')) {
76
+ dependencies['nodemailer'] = '^6.9.7';
77
+ if (isTypeScript) devDependencies['@types/nodemailer'] = '^6.4.14';
78
+ }
79
+
80
+ if (config.features.includes('cache')) {
81
+ dependencies['redis'] = '^4.6.12';
82
+ dependencies['ioredis'] = '^5.3.2';
83
+ if (isTypeScript) devDependencies['@types/redis'] = '^4.0.11';
84
+ }
85
+
86
+ if (config.features.includes('jobs')) {
87
+ dependencies['bull'] = '^4.12.0';
88
+ if (isTypeScript) devDependencies['@types/bull'] = '^4.10.0';
89
+ }
90
+
91
+ if (config.features.includes('cors')) {
92
+ if (isTypeScript) devDependencies['@types/cors'] = '^2.8.17';
93
+ }
94
+
95
+ // Testing dependencies
96
+ if (config.testing === 'jest') {
97
+ devDependencies['jest'] = '^29.7.0';
98
+ if (isTypeScript) {
99
+ devDependencies['@types/jest'] = '^29.5.11';
100
+ devDependencies['ts-jest'] = '^29.1.1';
101
+ }
102
+ } else if (config.testing === 'vitest') {
103
+ devDependencies['vitest'] = '^1.1.0';
104
+ } else if (config.testing === 'mocha') {
105
+ devDependencies['mocha'] = '^10.2.0';
106
+ devDependencies['chai'] = '^4.3.10';
107
+ if (isTypeScript) {
108
+ devDependencies['@types/mocha'] = '^10.0.6';
109
+ devDependencies['@types/chai'] = '^4.3.11';
110
+ }
111
+ }
112
+
113
+ const scripts = {
114
+ start: isTypeScript ? 'node dist/index.js' : 'node src/index.js',
115
+ dev: isTypeScript ? 'ts-node-dev --respawn --transpile-only src/index.ts' : 'nodemon src/index.js',
116
+ build: isTypeScript ? 'tsc' : 'echo "No build step required for JavaScript"',
117
+ lint: 'eslint src/**/*.' + (isTypeScript ? 'ts' : 'js'),
118
+ 'lint:fix': 'eslint src/**/*.' + (isTypeScript ? 'ts' : 'js') + ' --fix',
119
+ format: 'prettier --write "src/**/*.' + (isTypeScript ? 'ts' : 'js') + '"',
120
+ };
121
+
122
+ if (config.testing !== 'none') {
123
+ scripts.test = config.testing === 'jest' ? 'jest' : config.testing === 'vitest' ? 'vitest' : 'mocha';
124
+ scripts['test:watch'] = scripts.test + ' --watch';
125
+ scripts['test:coverage'] = scripts.test + ' --coverage';
126
+ }
127
+
128
+ return {
129
+ name: projectName,
130
+ version: '1.0.0',
131
+ description: 'A production-ready Node.js application',
132
+ main: isTypeScript ? 'dist/index.js' : 'src/index.js',
133
+ scripts,
134
+ keywords: [],
135
+ author: '',
136
+ license: 'MIT',
137
+ dependencies,
138
+ devDependencies,
139
+ };
140
+ }
141
+
142
+ module.exports = { generatePackageJson };