stackinit 0.1.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.
Files changed (63) hide show
  1. package/.editorconfig +18 -0
  2. package/.env.example +11 -0
  3. package/.eslintrc.json +30 -0
  4. package/.github/workflows/ci.yml +36 -0
  5. package/.prettierignore +11 -0
  6. package/.prettierrc.json +10 -0
  7. package/CONTRIBUTING.md +272 -0
  8. package/Dockerfile +36 -0
  9. package/LICENSE +22 -0
  10. package/README.md +202 -0
  11. package/dist/banner.d.ts +2 -0
  12. package/dist/banner.d.ts.map +1 -0
  13. package/dist/banner.js +16 -0
  14. package/dist/banner.js.map +1 -0
  15. package/dist/ci.d.ts +3 -0
  16. package/dist/ci.d.ts.map +1 -0
  17. package/dist/ci.js +83 -0
  18. package/dist/ci.js.map +1 -0
  19. package/dist/dependencies.d.ts +3 -0
  20. package/dist/dependencies.d.ts.map +1 -0
  21. package/dist/dependencies.js +102 -0
  22. package/dist/dependencies.js.map +1 -0
  23. package/dist/detect.d.ts +3 -0
  24. package/dist/detect.d.ts.map +1 -0
  25. package/dist/detect.js +125 -0
  26. package/dist/detect.js.map +1 -0
  27. package/dist/docker.d.ts +3 -0
  28. package/dist/docker.d.ts.map +1 -0
  29. package/dist/docker.js +100 -0
  30. package/dist/docker.js.map +1 -0
  31. package/dist/generate.d.ts +3 -0
  32. package/dist/generate.d.ts.map +1 -0
  33. package/dist/generate.js +71 -0
  34. package/dist/generate.js.map +1 -0
  35. package/dist/husky.d.ts +3 -0
  36. package/dist/husky.d.ts.map +1 -0
  37. package/dist/husky.js +92 -0
  38. package/dist/husky.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +128 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/templates.d.ts +11 -0
  44. package/dist/templates.d.ts.map +1 -0
  45. package/dist/templates.js +209 -0
  46. package/dist/templates.js.map +1 -0
  47. package/dist/types.d.ts +16 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +2 -0
  50. package/dist/types.js.map +1 -0
  51. package/docker-compose.yml +15 -0
  52. package/package.json +60 -0
  53. package/src/banner.ts +15 -0
  54. package/src/ci.ts +94 -0
  55. package/src/dependencies.ts +120 -0
  56. package/src/detect.ts +132 -0
  57. package/src/docker.ts +107 -0
  58. package/src/generate.ts +81 -0
  59. package/src/husky.ts +107 -0
  60. package/src/index.ts +145 -0
  61. package/src/templates.ts +244 -0
  62. package/src/types.ts +18 -0
  63. package/tsconfig.json +26 -0
package/dist/ci.js ADDED
@@ -0,0 +1,83 @@
1
+ import { mkdir, writeFile, access } from 'fs/promises';
2
+ import { join } from 'path';
3
+ export async function generateCI(projectInfo, options) {
4
+ const workflowsDir = join(projectInfo.rootPath, '.github', 'workflows');
5
+ try {
6
+ await mkdir(workflowsDir, { recursive: true });
7
+ }
8
+ catch {
9
+ // Directory might already exist
10
+ }
11
+ const ciYml = generateCIYml(projectInfo, options);
12
+ const ciPath = join(workflowsDir, 'ci.yml');
13
+ // Check if file already exists
14
+ try {
15
+ await access(ciPath);
16
+ console.log(' Skipping .github/workflows/ci.yml (already exists)');
17
+ return;
18
+ }
19
+ catch {
20
+ // File doesn't exist, proceed
21
+ }
22
+ await writeFile(ciPath, ciYml, 'utf-8');
23
+ console.log(' Generated .github/workflows/ci.yml');
24
+ }
25
+ function generateCIYml(projectInfo, options) {
26
+ const nodeVersion = '20';
27
+ const installCommand = getInstallCommand(projectInfo.packageManager);
28
+ // Build YAML content
29
+ let yaml = `name: CI
30
+
31
+ on:
32
+ push:
33
+ branches: [main, master, develop]
34
+ pull_request:
35
+ branches: [main, master, develop]
36
+
37
+ jobs:
38
+ ci:
39
+ runs-on: ubuntu-latest
40
+
41
+ steps:
42
+ - name: Checkout code
43
+ uses: actions/checkout@v4
44
+
45
+ - name: Setup Node.js
46
+ uses: actions/setup-node@v4
47
+ with:
48
+ node-version: '${nodeVersion}'
49
+ cache: '${projectInfo.packageManager}'
50
+
51
+ - name: Install dependencies
52
+ run: ${installCommand}
53
+
54
+ - name: Lint
55
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm lint' : 'npm run lint'}
56
+ ${options.strict ? '' : ' continue-on-error: true'}
57
+
58
+ `;
59
+ if (projectInfo.hasTypeScript) {
60
+ yaml += ` - name: Type check
61
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm type-check' : 'npm run type-check'}
62
+ ${options.strict ? '' : ' continue-on-error: true'}
63
+
64
+ `;
65
+ }
66
+ yaml += ` - name: Run tests
67
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm test' : 'npm test'}
68
+ continue-on-error: true
69
+ `;
70
+ return yaml;
71
+ }
72
+ function getInstallCommand(packageManager) {
73
+ switch (packageManager) {
74
+ case 'pnpm':
75
+ return 'pnpm install --frozen-lockfile';
76
+ case 'yarn':
77
+ return 'yarn install --frozen-lockfile';
78
+ case 'npm':
79
+ default:
80
+ return 'npm ci';
81
+ }
82
+ }
83
+ //# sourceMappingURL=ci.js.map
package/dist/ci.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,WAAwB,EAAE,OAAgB;IACzE,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IAExE,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;IAED,MAAM,KAAK,GAAG,aAAa,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAE5C,+BAA+B;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IAED,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,aAAa,CAAC,WAAwB,EAAE,OAAgB;IAC/D,MAAM,WAAW,GAAG,IAAI,CAAC;IACzB,MAAM,cAAc,GAAG,iBAAiB,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IAErE,qBAAqB;IACrB,IAAI,IAAI,GAAG;;;;;;;;;;;;;;;;;;;2BAmBc,WAAW;oBAClB,WAAW,CAAC,cAAc;;;eAG/B,cAAc;;;eAGd,WAAW,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;EACjF,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iCAAiC;;CAExD,CAAC;IAEA,IAAI,WAAW,CAAC,aAAa,EAAE,CAAC;QAC9B,IAAI,IAAI;eACG,WAAW,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,oBAAoB;EAC7F,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iCAAiC;;CAExD,CAAC;IACA,CAAC;IAED,IAAI,IAAI;eACK,WAAW,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU;;CAE9E,CAAC;IAEA,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CAAC,cAA6C;IACtE,QAAQ,cAAc,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO,gCAAgC,CAAC;QAC1C,KAAK,MAAM;YACT,OAAO,gCAAgC,CAAC;QAC1C,KAAK,KAAK,CAAC;QACX;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectInfo, Options } from './types.js';
2
+ export declare function addDependencies(projectInfo: ProjectInfo, options: Options): Promise<void>;
3
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAIvD,wBAAsB,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAuE/F"}
@@ -0,0 +1,102 @@
1
+ import { readFile, writeFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { exec } from 'child_process';
4
+ import { promisify } from 'util';
5
+ const execAsync = promisify(exec);
6
+ export async function addDependencies(projectInfo, options) {
7
+ const packageJsonPath = join(projectInfo.rootPath, 'package.json');
8
+ try {
9
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
10
+ // Initialize devDependencies if not present
11
+ if (!packageJson.devDependencies) {
12
+ packageJson.devDependencies = {};
13
+ }
14
+ // Core dependencies (always needed)
15
+ const coreDeps = {
16
+ eslint: '^8.57.0',
17
+ prettier: '^3.2.0',
18
+ husky: '^9.0.0',
19
+ 'lint-staged': '^15.2.0',
20
+ };
21
+ // TypeScript dependencies
22
+ if (projectInfo.hasTypeScript) {
23
+ coreDeps['@typescript-eslint/parser'] = '^6.19.0';
24
+ coreDeps['@typescript-eslint/eslint-plugin'] = '^6.19.0';
25
+ }
26
+ // React dependencies
27
+ const isReact = projectInfo.type === 'react' ||
28
+ projectInfo.type === 'nextjs' ||
29
+ projectInfo.type === 'vite';
30
+ if (isReact) {
31
+ coreDeps['eslint-plugin-react'] = '^7.33.0';
32
+ coreDeps['eslint-plugin-react-hooks'] = '^4.6.0';
33
+ }
34
+ // Next.js specific
35
+ if (projectInfo.type === 'nextjs') {
36
+ coreDeps['eslint-config-next'] = 'latest';
37
+ }
38
+ // Commitlint (strict mode)
39
+ if (options.strict) {
40
+ coreDeps['@commitlint/cli'] = '^18.6.0';
41
+ coreDeps['@commitlint/config-conventional'] = '^18.6.0';
42
+ }
43
+ // Add dependencies only if they don't already exist
44
+ let hasNewDeps = false;
45
+ for (const [dep, version] of Object.entries(coreDeps)) {
46
+ if (!packageJson.devDependencies[dep] && !packageJson.dependencies?.[dep]) {
47
+ packageJson.devDependencies[dep] = version;
48
+ hasNewDeps = true;
49
+ }
50
+ }
51
+ if (hasNewDeps) {
52
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8');
53
+ console.log(' Updated package.json with dependencies');
54
+ // Install dependencies
55
+ await installDependencies(projectInfo);
56
+ }
57
+ else {
58
+ console.log(' All required dependencies already present');
59
+ }
60
+ }
61
+ catch (error) {
62
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
63
+ console.warn(' Warning: package.json not found, skipping dependency installation');
64
+ }
65
+ else {
66
+ throw error;
67
+ }
68
+ }
69
+ }
70
+ async function installDependencies(projectInfo) {
71
+ const { packageManager } = projectInfo;
72
+ const rootPath = projectInfo.rootPath;
73
+ console.log(`\n Installing dependencies with ${packageManager}...`);
74
+ try {
75
+ let installCommand;
76
+ switch (packageManager) {
77
+ case 'pnpm':
78
+ installCommand = 'pnpm install';
79
+ break;
80
+ case 'yarn':
81
+ installCommand = 'yarn install';
82
+ break;
83
+ case 'npm':
84
+ default:
85
+ installCommand = 'npm install';
86
+ break;
87
+ }
88
+ await execAsync(installCommand, {
89
+ cwd: rootPath,
90
+ maxBuffer: 10 * 1024 * 1024, // 10MB buffer
91
+ });
92
+ console.log(' Dependencies installed successfully');
93
+ }
94
+ catch {
95
+ console.error(' Failed to install dependencies automatically');
96
+ console.error(' Please run manually:', packageManager === 'pnpm' ? 'pnpm install' :
97
+ packageManager === 'yarn' ? 'yarn install' :
98
+ 'npm install');
99
+ // Don't throw - let the user install manually if needed
100
+ }
101
+ }
102
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../src/dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectInfo } from './types.js';
2
+ export declare function detectProject(): Promise<ProjectInfo>;
3
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,YAAY,CAAC;AAE3E,wBAAsB,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,CAiB1D"}
package/dist/detect.js ADDED
@@ -0,0 +1,125 @@
1
+ import { readFile, access } from 'fs/promises';
2
+ import { join } from 'path';
3
+ export async function detectProject() {
4
+ const rootPath = process.cwd();
5
+ const [type, packageManager, hasTypeScript, isMonorepo] = await Promise.all([
6
+ detectProjectType(rootPath),
7
+ detectPackageManager(rootPath),
8
+ detectTypeScript(rootPath),
9
+ detectMonorepo(rootPath),
10
+ ]);
11
+ return {
12
+ type,
13
+ packageManager,
14
+ hasTypeScript,
15
+ isMonorepo,
16
+ rootPath,
17
+ };
18
+ }
19
+ async function detectProjectType(rootPath) {
20
+ try {
21
+ const packageJsonPath = join(rootPath, 'package.json');
22
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
23
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
24
+ // Check for Next.js
25
+ if (deps.next || deps['nextjs']) {
26
+ return 'nextjs';
27
+ }
28
+ // Check for Vite
29
+ if (deps.vite || deps['@vitejs/plugin-react']) {
30
+ return 'vite';
31
+ }
32
+ // Check for React
33
+ if (deps.react || deps['react-dom']) {
34
+ return 'react';
35
+ }
36
+ // Default to Node backend
37
+ return 'node';
38
+ }
39
+ catch {
40
+ return 'unknown';
41
+ }
42
+ }
43
+ async function detectPackageManager(rootPath) {
44
+ // Check for lock files
45
+ const lockFiles = [
46
+ { file: 'pnpm-lock.yaml', manager: 'pnpm' },
47
+ { file: 'yarn.lock', manager: 'yarn' },
48
+ { file: 'package-lock.json', manager: 'npm' },
49
+ ];
50
+ for (const { file, manager } of lockFiles) {
51
+ try {
52
+ await access(join(rootPath, file));
53
+ return manager;
54
+ }
55
+ catch {
56
+ // Continue checking
57
+ }
58
+ }
59
+ // Check for packageManager field in package.json
60
+ try {
61
+ const packageJsonPath = join(rootPath, 'package.json');
62
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
63
+ if (packageJson.packageManager) {
64
+ if (packageJson.packageManager.startsWith('pnpm'))
65
+ return 'pnpm';
66
+ if (packageJson.packageManager.startsWith('yarn'))
67
+ return 'yarn';
68
+ if (packageJson.packageManager.startsWith('npm'))
69
+ return 'npm';
70
+ }
71
+ }
72
+ catch {
73
+ // Fall through
74
+ }
75
+ // Default to npm
76
+ return 'npm';
77
+ }
78
+ async function detectTypeScript(rootPath) {
79
+ try {
80
+ const tsConfigPath = join(rootPath, 'tsconfig.json');
81
+ await access(tsConfigPath);
82
+ return true;
83
+ }
84
+ catch {
85
+ // Check for TypeScript in dependencies
86
+ try {
87
+ const packageJsonPath = join(rootPath, 'package.json');
88
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
89
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
90
+ return 'typescript' in deps;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ }
97
+ async function detectMonorepo(rootPath) {
98
+ // Check for common monorepo indicators
99
+ const indicators = [
100
+ 'pnpm-workspace.yaml',
101
+ 'lerna.json',
102
+ 'nx.json',
103
+ 'turbo.json',
104
+ 'rush.json',
105
+ ];
106
+ for (const indicator of indicators) {
107
+ try {
108
+ await access(join(rootPath, indicator));
109
+ return true;
110
+ }
111
+ catch {
112
+ // Continue checking
113
+ }
114
+ }
115
+ // Check package.json for workspaces
116
+ try {
117
+ const packageJsonPath = join(rootPath, 'package.json');
118
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
119
+ return !!(packageJson.workspaces || packageJson.workspace);
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../src/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectInfo } from './types.js';
2
+ export declare function generateDocker(projectInfo: ProjectInfo): Promise<void>;
3
+ //# sourceMappingURL=docker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../src/docker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAsB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5E"}
package/dist/docker.js ADDED
@@ -0,0 +1,100 @@
1
+ import { writeFile, access } from 'fs/promises';
2
+ import { join } from 'path';
3
+ export async function generateDocker(projectInfo) {
4
+ const dockerfile = generateDockerfile(projectInfo);
5
+ const dockerCompose = generateDockerCompose();
6
+ const dockerfilePath = join(projectInfo.rootPath, 'Dockerfile');
7
+ const dockerComposePath = join(projectInfo.rootPath, 'docker-compose.yml');
8
+ // Check if files exist
9
+ try {
10
+ await access(dockerfilePath);
11
+ console.log(' Skipping Dockerfile (already exists)');
12
+ }
13
+ catch {
14
+ await writeFile(dockerfilePath, dockerfile, 'utf-8');
15
+ console.log(' Generated Dockerfile');
16
+ }
17
+ try {
18
+ await access(dockerComposePath);
19
+ console.log(' Skipping docker-compose.yml (already exists)');
20
+ }
21
+ catch {
22
+ await writeFile(dockerComposePath, dockerCompose, 'utf-8');
23
+ console.log(' Generated docker-compose.yml');
24
+ }
25
+ }
26
+ function generateDockerfile(projectInfo) {
27
+ const packageManager = projectInfo.packageManager;
28
+ const installCmd = packageManager === 'pnpm'
29
+ ? 'RUN pnpm install --frozen-lockfile'
30
+ : packageManager === 'yarn'
31
+ ? 'RUN yarn install --frozen-lockfile'
32
+ : 'RUN npm ci';
33
+ const lockFileName = packageManager === 'pnpm'
34
+ ? 'pnpm-lock.yaml'
35
+ : packageManager === 'yarn'
36
+ ? 'yarn.lock'
37
+ : 'package-lock.json';
38
+ return `# Build stage
39
+ FROM node:20-alpine AS builder
40
+
41
+ WORKDIR /app
42
+
43
+ # Copy package files
44
+ COPY package.json .
45
+ COPY ${lockFileName} .
46
+
47
+ ${installCmd}
48
+
49
+ # Copy source files
50
+ COPY . .
51
+
52
+ # Build the application (adjust as needed)
53
+ ${projectInfo.hasTypeScript ? 'RUN npm run build' : '# Add build command if needed'}
54
+
55
+ # Production stage
56
+ FROM node:20-alpine AS production
57
+
58
+ WORKDIR /app
59
+
60
+ # Copy package files
61
+ COPY package.json .
62
+ COPY ${lockFileName} .
63
+
64
+ # Install production dependencies only
65
+ ${packageManager === 'pnpm'
66
+ ? 'RUN pnpm install --frozen-lockfile --prod'
67
+ : packageManager === 'yarn'
68
+ ? 'RUN yarn install --frozen-lockfile --production'
69
+ : 'RUN npm ci --only=production'}
70
+
71
+ # Copy built application from builder
72
+ COPY --from=builder /app/dist ./dist
73
+ COPY --from=builder /app/public ./public 2>/dev/null || true
74
+
75
+ # Expose port (adjust as needed)
76
+ EXPOSE 3000
77
+
78
+ # Start the application
79
+ CMD ["node", "dist/index.js"]
80
+ `;
81
+ }
82
+ function generateDockerCompose() {
83
+ return `version: '3.8'
84
+
85
+ services:
86
+ app:
87
+ build:
88
+ context: .
89
+ dockerfile: Dockerfile
90
+ target: production
91
+ ports:
92
+ - "3000:3000"
93
+ environment:
94
+ - NODE_ENV=production
95
+ restart: unless-stopped
96
+ # volumes:
97
+ # - ./data:/app/data
98
+ `;
99
+ }
100
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../src/docker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAwB;IAC3D,MAAM,UAAU,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,qBAAqB,EAAE,CAAC;IAE9C,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAChE,MAAM,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IAE3E,uBAAuB;IACvB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,cAAc,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACxC,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,iBAAiB,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,WAAwB;IAClD,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,CAAC;IAClD,MAAM,UAAU,GAAG,cAAc,KAAK,MAAM;QAC1C,CAAC,CAAC,oCAAoC;QACtC,CAAC,CAAC,cAAc,KAAK,MAAM;YAC3B,CAAC,CAAC,oCAAoC;YACtC,CAAC,CAAC,YAAY,CAAC;IAEjB,MAAM,YAAY,GAAG,cAAc,KAAK,MAAM;QAC5C,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,cAAc,KAAK,MAAM;YAC3B,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,mBAAmB,CAAC;IAExB,OAAO;;;;;;;OAOF,YAAY;;EAEjB,UAAU;;;;;;EAMV,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,+BAA+B;;;;;;;;;OAS5E,YAAY;;;EAGjB,cAAc,KAAK,MAAM;QACzB,CAAC,CAAC,2CAA2C;QAC7C,CAAC,CAAC,cAAc,KAAK,MAAM;YAC3B,CAAC,CAAC,iDAAiD;YACnD,CAAC,CAAC,8BAA8B;;;;;;;;;;;CAWjC,CAAC;AACF,CAAC;AAED,SAAS,qBAAqB;IAC5B,OAAO;;;;;;;;;;;;;;;CAeR,CAAC;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectInfo, Options } from './types.js';
2
+ export declare function generateFiles(projectInfo: ProjectInfo, options: Options): Promise<void>;
3
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGvD,wBAAsB,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA6B7F"}
@@ -0,0 +1,71 @@
1
+ import { writeFile, readFile, access } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { getTemplates } from './templates.js';
4
+ export async function generateFiles(projectInfo, options) {
5
+ const templates = getTemplates(projectInfo, options);
6
+ const filesToGenerate = [
7
+ { name: '.eslintrc.json', content: templates.eslint },
8
+ { name: '.prettierrc.json', content: templates.prettier },
9
+ { name: '.prettierignore', content: templates.prettierIgnore },
10
+ { name: '.gitignore', content: templates.gitignore },
11
+ { name: '.editorconfig', content: templates.editorconfig },
12
+ { name: '.env.example', content: templates.envExample },
13
+ ];
14
+ for (const file of filesToGenerate) {
15
+ const filePath = join(projectInfo.rootPath, file.name);
16
+ // Skip if file exists (don't overwrite)
17
+ try {
18
+ await access(filePath);
19
+ console.log(` Skipping ${file.name} (already exists)`);
20
+ continue;
21
+ }
22
+ catch {
23
+ // File doesn't exist, proceed
24
+ }
25
+ await writeFile(filePath, file.content, 'utf-8');
26
+ console.log(` Generated ${file.name}`);
27
+ }
28
+ // Update package.json scripts
29
+ await updatePackageJson(projectInfo);
30
+ }
31
+ async function updatePackageJson(projectInfo) {
32
+ const packageJsonPath = join(projectInfo.rootPath, 'package.json');
33
+ try {
34
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
35
+ // Initialize scripts if not present
36
+ if (!packageJson.scripts) {
37
+ packageJson.scripts = {};
38
+ }
39
+ // Add scripts only if they don't exist
40
+ const scriptsToAdd = {
41
+ lint: projectInfo.hasTypeScript
42
+ ? 'eslint . --ext .js,.jsx,.ts,.tsx'
43
+ : 'eslint . --ext .js,.jsx',
44
+ 'lint:fix': projectInfo.hasTypeScript
45
+ ? 'eslint . --ext .js,.jsx,.ts,.tsx --fix'
46
+ : 'eslint . --ext .js,.jsx --fix',
47
+ format: 'prettier --write "**/*.{js,jsx,ts,tsx,json,md}"',
48
+ 'format:check': 'prettier --check "**/*.{js,jsx,ts,tsx,json,md}"',
49
+ };
50
+ if (projectInfo.hasTypeScript) {
51
+ scriptsToAdd['type-check'] = 'tsc --noEmit';
52
+ }
53
+ // Only add scripts that don't already exist
54
+ for (const [key, value] of Object.entries(scriptsToAdd)) {
55
+ if (!packageJson.scripts[key]) {
56
+ packageJson.scripts[key] = value;
57
+ }
58
+ }
59
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8');
60
+ console.log(' Updated package.json scripts');
61
+ }
62
+ catch (error) {
63
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
64
+ console.warn(' Warning: package.json not found, skipping script updates');
65
+ }
66
+ else {
67
+ throw error;
68
+ }
69
+ }
70
+ }
71
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ProjectInfo, Options } from './types.js';
2
+ export declare function setupHusky(projectInfo: ProjectInfo, options: Options): Promise<void>;
3
+ //# sourceMappingURL=husky.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"husky.d.ts","sourceRoot":"","sources":["../src/husky.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEvD,wBAAsB,UAAU,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD1F"}
package/dist/husky.js ADDED
@@ -0,0 +1,92 @@
1
+ import { writeFile, mkdir, access, readFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ export async function setupHusky(projectInfo, options) {
4
+ const huskyDir = join(projectInfo.rootPath, '.husky');
5
+ // Check if .git exists
6
+ try {
7
+ await access(join(projectInfo.rootPath, '.git'));
8
+ }
9
+ catch {
10
+ console.warn(' Warning: .git directory not found, skipping Husky setup');
11
+ return;
12
+ }
13
+ // Create .husky directory
14
+ try {
15
+ await mkdir(huskyDir, { recursive: true });
16
+ }
17
+ catch {
18
+ // Directory might already exist
19
+ }
20
+ // Create pre-commit hook
21
+ const preCommitHook = `#!/usr/bin/env sh
22
+ . "$(dirname -- "$0")/_/husky.sh"
23
+
24
+ ${projectInfo.packageManager === 'pnpm' ? 'pnpm' : 'npx'} lint-staged
25
+ `;
26
+ const preCommitPath = join(huskyDir, 'pre-commit');
27
+ await writeFile(preCommitPath, preCommitHook, 'utf-8');
28
+ // Make it executable (Unix-like systems)
29
+ if (process.platform !== 'win32') {
30
+ const { chmod } = await import('fs/promises');
31
+ await chmod(preCommitPath, 0o755);
32
+ }
33
+ // Create commit-msg hook if commitlint is enabled
34
+ if (options.strict) {
35
+ const commitMsgHook = `#!/usr/bin/env sh
36
+ . "$(dirname -- "$0")/_/husky.sh"
37
+
38
+ ${projectInfo.packageManager === 'pnpm' ? 'pnpm' : 'npx'} commitlint --edit "$1"
39
+ `;
40
+ const commitMsgPath = join(huskyDir, 'commit-msg');
41
+ await writeFile(commitMsgPath, commitMsgHook, 'utf-8');
42
+ if (process.platform !== 'win32') {
43
+ const { chmod } = await import('fs/promises');
44
+ await chmod(commitMsgPath, 0o755);
45
+ }
46
+ }
47
+ // Update package.json with husky and lint-staged config
48
+ await updatePackageJsonForHusky(projectInfo, options);
49
+ }
50
+ async function updatePackageJsonForHusky(projectInfo, options) {
51
+ const packageJsonPath = join(projectInfo.rootPath, 'package.json');
52
+ try {
53
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
54
+ // Add prepare script for husky
55
+ if (!packageJson.scripts) {
56
+ packageJson.scripts = {};
57
+ }
58
+ if (!packageJson.scripts.prepare) {
59
+ packageJson.scripts.prepare = 'husky install';
60
+ }
61
+ // Add lint-staged configuration
62
+ if (!packageJson['lint-staged']) {
63
+ const lintStagedConfig = {
64
+ '*.{js,jsx,ts,tsx}': [
65
+ 'eslint --fix',
66
+ 'prettier --write',
67
+ ],
68
+ '*.{json,md,yml,yaml}': [
69
+ 'prettier --write',
70
+ ],
71
+ };
72
+ packageJson['lint-staged'] = lintStagedConfig;
73
+ }
74
+ // Add commitlint config if strict mode
75
+ if (options.strict && !packageJson.commitlint) {
76
+ packageJson.commitlint = {
77
+ extends: ['@commitlint/config-conventional'],
78
+ };
79
+ }
80
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8');
81
+ console.log(' Configured Husky git hooks');
82
+ }
83
+ catch (error) {
84
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
85
+ console.warn(' Warning: package.json not found, skipping Husky configuration');
86
+ }
87
+ else {
88
+ throw error;
89
+ }
90
+ }
91
+ }
92
+ //# sourceMappingURL=husky.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"husky.js","sourceRoot":"","sources":["../src/husky.ts"],"names":[],"mappings":"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"}