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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { detectProject } from './detect.js';
4
+ import { generateFiles } from './generate.js';
5
+ import { setupHusky } from './husky.js';
6
+ import { generateCI } from './ci.js';
7
+ import { generateDocker } from './docker.js';
8
+ import { addDependencies } from './dependencies.js';
9
+ import { printBanner } from './banner.js';
10
+ import { exec } from 'child_process';
11
+ import { promisify } from 'util';
12
+ const execAsync = promisify(exec);
13
+ const program = new Command();
14
+ program
15
+ .name('stackinit')
16
+ .description('Initialize a consistent development environment for Node-based projects')
17
+ .version('0.1.0')
18
+ .option('--strict', 'Enable stricter lint rules and CI failure on warnings')
19
+ .option('--docker', 'Generate Dockerfile and docker-compose.yml')
20
+ .option('--ci-only', 'Generate only GitHub Actions')
21
+ .option('--dry-run', 'Show what files would be created without writing')
22
+ .action(async (options) => {
23
+ try {
24
+ if (!options.dryRun && !options.ciOnly) {
25
+ printBanner();
26
+ }
27
+ const projectInfo = await detectProject();
28
+ if (options.dryRun) {
29
+ console.log('\nDRY RUN MODE - No files will be written\n');
30
+ console.log('Detected project:');
31
+ console.log(` Type: ${projectInfo.type}`);
32
+ console.log(` Package Manager: ${projectInfo.packageManager}`);
33
+ console.log(` TypeScript: ${projectInfo.hasTypeScript ? 'Yes' : 'No'}`);
34
+ console.log(` Monorepo: ${projectInfo.isMonorepo ? 'Yes' : 'No'}\n`);
35
+ console.log('Files that would be generated:');
36
+ console.log(' - .eslintrc.json');
37
+ console.log(' - .prettierrc.json');
38
+ console.log(' - .prettierignore');
39
+ console.log(' - .gitignore');
40
+ console.log(' - .editorconfig');
41
+ console.log(' - .env.example');
42
+ console.log(' - .husky/pre-commit');
43
+ if (options.strict) {
44
+ console.log(' - .husky/commit-msg');
45
+ }
46
+ console.log(' - .github/workflows/ci.yml');
47
+ if (options.docker) {
48
+ console.log(' - Dockerfile');
49
+ console.log(' - docker-compose.yml');
50
+ }
51
+ console.log('\nPackage.json scripts that would be added:');
52
+ console.log(' - lint');
53
+ console.log(' - lint:fix');
54
+ console.log(' - format');
55
+ console.log(' - format:check');
56
+ if (projectInfo.hasTypeScript) {
57
+ console.log(' - type-check');
58
+ }
59
+ console.log(' - prepare (for Husky)');
60
+ console.log('\nDependencies that would be installed:');
61
+ console.log(' - eslint, prettier, husky, lint-staged');
62
+ if (projectInfo.hasTypeScript) {
63
+ console.log(' - @typescript-eslint/parser, @typescript-eslint/eslint-plugin');
64
+ }
65
+ if (projectInfo.type === 'react' || projectInfo.type === 'nextjs' || projectInfo.type === 'vite') {
66
+ console.log(' - eslint-plugin-react, eslint-plugin-react-hooks');
67
+ }
68
+ if (projectInfo.type === 'nextjs') {
69
+ console.log(' - eslint-config-next');
70
+ }
71
+ if (options.strict) {
72
+ console.log(' - @commitlint/cli, @commitlint/config-conventional');
73
+ }
74
+ return;
75
+ }
76
+ if (options.ciOnly) {
77
+ await generateCI(projectInfo, options);
78
+ console.log('\n✓ GitHub Actions CI generated successfully');
79
+ return;
80
+ }
81
+ console.log('\nInitializing development environment...\n');
82
+ // Generate core config files
83
+ await generateFiles(projectInfo, options);
84
+ // Add and install dependencies
85
+ await addDependencies(projectInfo, options);
86
+ // Setup Husky and lint-staged
87
+ await setupHusky(projectInfo, options);
88
+ // Initialize Husky (if git repo exists)
89
+ await initializeHusky(projectInfo);
90
+ // Generate CI
91
+ await generateCI(projectInfo, options);
92
+ // Generate Docker files if requested
93
+ if (options.docker) {
94
+ await generateDocker(projectInfo);
95
+ }
96
+ console.log('\n✓ Development environment initialized successfully\n');
97
+ console.log('Next steps:');
98
+ console.log(' 1. Review the generated configuration files');
99
+ console.log(' 2. Start developing!\n');
100
+ }
101
+ catch (error) {
102
+ console.error('\nERROR:', error instanceof Error ? error.message : String(error));
103
+ process.exit(1);
104
+ }
105
+ });
106
+ async function initializeHusky(projectInfo) {
107
+ try {
108
+ const { access } = await import('fs/promises');
109
+ await access(projectInfo.rootPath + '/.git');
110
+ // Husky install
111
+ const huskyCommand = projectInfo.packageManager === 'pnpm'
112
+ ? 'pnpm exec husky install'
113
+ : 'npx husky install';
114
+ try {
115
+ await execAsync(huskyCommand, { cwd: projectInfo.rootPath });
116
+ console.log('✓ Husky initialized');
117
+ }
118
+ catch {
119
+ // Husky install might fail if not in git repo or already installed
120
+ // This is okay, user can run manually if needed
121
+ }
122
+ }
123
+ catch {
124
+ // Not a git repo, skip husky init
125
+ }
126
+ }
127
+ program.parse();
128
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ProjectInfo, Options } from './types.js';
2
+ export interface Templates {
3
+ eslint: string;
4
+ prettier: string;
5
+ prettierIgnore: string;
6
+ gitignore: string;
7
+ editorconfig: string;
8
+ envExample: string;
9
+ }
10
+ export declare function getTemplates(projectInfo: ProjectInfo, options: Options): Templates;
11
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,CASlF"}
@@ -0,0 +1,209 @@
1
+ export function getTemplates(projectInfo, options) {
2
+ return {
3
+ eslint: getESLintConfig(projectInfo, options),
4
+ prettier: getPrettierConfig(),
5
+ prettierIgnore: getPrettierIgnore(),
6
+ gitignore: getGitignore(projectInfo),
7
+ editorconfig: getEditorConfig(),
8
+ envExample: getEnvExample(projectInfo),
9
+ };
10
+ }
11
+ function getESLintConfig(projectInfo, options) {
12
+ const isStrict = options.strict ?? false;
13
+ const hasTypeScript = projectInfo.hasTypeScript;
14
+ const isReact = projectInfo.type === 'react' || projectInfo.type === 'nextjs' || projectInfo.type === 'vite';
15
+ const config = {
16
+ root: true,
17
+ env: {
18
+ node: true,
19
+ es2022: true,
20
+ ...(isReact && { browser: true }),
21
+ },
22
+ extends: [],
23
+ parserOptions: {
24
+ ecmaVersion: 2022,
25
+ sourceType: 'module',
26
+ },
27
+ rules: {
28
+ 'no-console': isStrict ? 'error' : 'warn',
29
+ 'no-debugger': isStrict ? 'error' : 'warn',
30
+ 'no-unused-vars': isStrict ? 'error' : 'warn',
31
+ 'prefer-const': 'error',
32
+ 'no-var': 'error',
33
+ },
34
+ };
35
+ if (hasTypeScript) {
36
+ config.parser = '@typescript-eslint/parser';
37
+ config.plugins = ['@typescript-eslint'];
38
+ config.extends.push('eslint:recommended', 'plugin:@typescript-eslint/recommended', ...(isStrict ? ['plugin:@typescript-eslint/recommended-requiring-type-checking'] : []));
39
+ config.parserOptions = {
40
+ ...config.parserOptions,
41
+ project: './tsconfig.json',
42
+ };
43
+ config.rules = {
44
+ ...config.rules,
45
+ '@typescript-eslint/no-unused-vars': isStrict ? 'error' : 'warn',
46
+ '@typescript-eslint/explicit-function-return-type': isStrict ? 'warn' : 'off',
47
+ '@typescript-eslint/no-explicit-any': isStrict ? 'error' : 'warn',
48
+ };
49
+ }
50
+ else {
51
+ config.extends.push('eslint:recommended');
52
+ }
53
+ if (isReact) {
54
+ config.extends.push('plugin:react/recommended', 'plugin:react-hooks/recommended');
55
+ config.settings = {
56
+ react: {
57
+ version: 'detect',
58
+ },
59
+ };
60
+ config.rules = {
61
+ ...config.rules,
62
+ 'react/react-in-jsx-scope': 'off', // Not needed in React 17+
63
+ 'react/prop-types': 'off', // TypeScript handles this
64
+ };
65
+ }
66
+ if (projectInfo.type === 'nextjs') {
67
+ config.extends.push('plugin:@next/next/recommended');
68
+ }
69
+ return JSON.stringify(config, null, 2);
70
+ }
71
+ function getPrettierConfig() {
72
+ return JSON.stringify({
73
+ semi: true,
74
+ trailingComma: 'es5',
75
+ singleQuote: true,
76
+ printWidth: 80,
77
+ tabWidth: 2,
78
+ useTabs: false,
79
+ arrowParens: 'always',
80
+ endOfLine: 'lf',
81
+ }, null, 2);
82
+ }
83
+ function getPrettierIgnore() {
84
+ return `node_modules
85
+ dist
86
+ build
87
+ .next
88
+ .nuxt
89
+ .cache
90
+ coverage
91
+ *.log
92
+ .DS_Store
93
+ .env
94
+ .env.local
95
+ `;
96
+ }
97
+ function getGitignore(projectInfo) {
98
+ const base = `# Dependencies
99
+ node_modules/
100
+ .pnp
101
+ .pnp.js
102
+
103
+ # Testing
104
+ coverage/
105
+ *.lcov
106
+ .nyc_output
107
+
108
+ # Production
109
+ dist/
110
+ build/
111
+ .next/
112
+ out/
113
+ .nuxt/
114
+ .cache/
115
+
116
+ # Misc
117
+ .DS_Store
118
+ *.pem
119
+ *.log
120
+ npm-debug.log*
121
+ yarn-debug.log*
122
+ yarn-error.log*
123
+ pnpm-debug.log*
124
+ lerna-debug.log*
125
+
126
+ # Local env files
127
+ .env
128
+ .env*.local
129
+ .env.development.local
130
+ .env.test.local
131
+ .env.production.local
132
+
133
+ # IDE
134
+ .vscode/
135
+ .idea/
136
+ *.swp
137
+ *.swo
138
+ *~
139
+
140
+ # OS
141
+ Thumbs.db
142
+ `;
143
+ if (projectInfo.type === 'nextjs') {
144
+ return base + `
145
+ # Next.js
146
+ .next/
147
+ out/
148
+ `;
149
+ }
150
+ if (projectInfo.type === 'vite') {
151
+ return base + `
152
+ # Vite
153
+ dist/
154
+ dist-ssr/
155
+ *.local
156
+ `;
157
+ }
158
+ return base;
159
+ }
160
+ function getEditorConfig() {
161
+ return `root = true
162
+
163
+ [*]
164
+ charset = utf-8
165
+ end_of_line = lf
166
+ indent_style = space
167
+ indent_size = 2
168
+ insert_final_newline = true
169
+ trim_trailing_whitespace = true
170
+
171
+ [*.md]
172
+ trim_trailing_whitespace = false
173
+
174
+ [*.{yml,yaml}]
175
+ indent_size = 2
176
+
177
+ [Makefile]
178
+ indent_style = tab
179
+ `;
180
+ }
181
+ function getEnvExample(projectInfo) {
182
+ const base = `# Environment variables
183
+ # Copy this file to .env and fill in the values
184
+
185
+ NODE_ENV=development
186
+ PORT=3000
187
+ `;
188
+ if (projectInfo.type === 'nextjs') {
189
+ return base + `
190
+ # Next.js
191
+ NEXT_PUBLIC_API_URL=http://localhost:3000/api
192
+ `;
193
+ }
194
+ if (projectInfo.type === 'react' || projectInfo.type === 'vite') {
195
+ return base + `
196
+ # API
197
+ VITE_API_URL=http://localhost:3000/api
198
+ REACT_APP_API_URL=http://localhost:3000/api
199
+ `;
200
+ }
201
+ return base + `
202
+ # Database (example)
203
+ # DATABASE_URL=postgresql://user:password@localhost:5432/dbname
204
+
205
+ # API Keys (example)
206
+ # API_KEY=your-api-key-here
207
+ `;
208
+ }
209
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export type ProjectType = 'node' | 'react' | 'nextjs' | 'vite' | 'unknown';
2
+ export type PackageManager = 'npm' | 'yarn' | 'pnpm';
3
+ export interface ProjectInfo {
4
+ type: ProjectType;
5
+ packageManager: PackageManager;
6
+ hasTypeScript: boolean;
7
+ isMonorepo: boolean;
8
+ rootPath: string;
9
+ }
10
+ export interface Options {
11
+ strict?: boolean;
12
+ docker?: boolean;
13
+ ciOnly?: boolean;
14
+ dryRun?: boolean;
15
+ }
16
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAC3E,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ app:
5
+ build:
6
+ context: .
7
+ dockerfile: Dockerfile
8
+ target: production
9
+ ports:
10
+ - "3000:3000"
11
+ environment:
12
+ - NODE_ENV=production
13
+ restart: unless-stopped
14
+ # volumes:
15
+ # - ./data:/app/data
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "stackinit",
3
+ "version": "0.1.0",
4
+ "description": "Initialize a consistent development environment for Node-based projects",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "stackinit": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "start": "node dist/index.js",
14
+ "prepublishOnly": "npm run build",
15
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
16
+ "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
17
+ "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
18
+ "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,md}\"",
19
+ "type-check": "tsc --noEmit"
20
+ },
21
+ "keywords": [
22
+ "cli",
23
+ "init",
24
+ "boilerplate",
25
+ "development",
26
+ "tooling",
27
+ "eslint",
28
+ "prettier",
29
+ "husky"
30
+ ],
31
+ "author": "",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/nupurkale78/stackinit.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/nupurkale78/stackinit/issues"
39
+ },
40
+ "homepage": "https://github.com/nupurkale78/stackinit#readme",
41
+ "dependencies": {
42
+ "commander": "^11.1.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20.10.0",
46
+ "tsx": "^4.7.0",
47
+ "typescript": "^5.3.3",
48
+ "eslint": "^8.57.0",
49
+ "prettier": "^3.2.0",
50
+ "husky": "^9.0.0",
51
+ "lint-staged": "^15.2.0",
52
+ "@typescript-eslint/parser": "^6.19.0",
53
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
54
+ "@commitlint/cli": "^18.6.0",
55
+ "@commitlint/config-conventional": "^18.6.0"
56
+ },
57
+ "engines": {
58
+ "node": ">=18.0.0"
59
+ }
60
+ }
package/src/banner.ts ADDED
@@ -0,0 +1,15 @@
1
+ export function printBanner(): void {
2
+ const banner = `
3
+ ╔═══════════════════════════════════════════════════════════════════════╗
4
+ ║ ║
5
+ ║ ║
6
+ ║ S T A C K I N I T ║
7
+ ║ ║
8
+ ║ ║
9
+ ║ Initialize your development environment ║
10
+ ║ ║
11
+ ║ ║
12
+ ╚═══════════════════════════════════════════════════════════════════════╝
13
+ `;
14
+ console.log(banner);
15
+ }
package/src/ci.ts ADDED
@@ -0,0 +1,94 @@
1
+ import { mkdir, writeFile, access } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import type { ProjectInfo, Options } from './types.js';
4
+
5
+ export async function generateCI(projectInfo: ProjectInfo, options: Options): Promise<void> {
6
+ const workflowsDir = join(projectInfo.rootPath, '.github', 'workflows');
7
+
8
+ try {
9
+ await mkdir(workflowsDir, { recursive: true });
10
+ } catch {
11
+ // Directory might already exist
12
+ }
13
+
14
+ const ciYml = generateCIYml(projectInfo, options);
15
+ const ciPath = join(workflowsDir, 'ci.yml');
16
+
17
+ // Check if file already exists
18
+ try {
19
+ await access(ciPath);
20
+ console.log(' Skipping .github/workflows/ci.yml (already exists)');
21
+ return;
22
+ } catch {
23
+ // File doesn't exist, proceed
24
+ }
25
+
26
+ await writeFile(ciPath, ciYml, 'utf-8');
27
+ console.log(' Generated .github/workflows/ci.yml');
28
+ }
29
+
30
+ function generateCIYml(projectInfo: ProjectInfo, options: Options): string {
31
+ const nodeVersion = '20';
32
+ const installCommand = getInstallCommand(projectInfo.packageManager);
33
+
34
+ // Build YAML content
35
+ let yaml = `name: CI
36
+
37
+ on:
38
+ push:
39
+ branches: [main, master, develop]
40
+ pull_request:
41
+ branches: [main, master, develop]
42
+
43
+ jobs:
44
+ ci:
45
+ runs-on: ubuntu-latest
46
+
47
+ steps:
48
+ - name: Checkout code
49
+ uses: actions/checkout@v4
50
+
51
+ - name: Setup Node.js
52
+ uses: actions/setup-node@v4
53
+ with:
54
+ node-version: '${nodeVersion}'
55
+ cache: '${projectInfo.packageManager}'
56
+
57
+ - name: Install dependencies
58
+ run: ${installCommand}
59
+
60
+ - name: Lint
61
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm lint' : 'npm run lint'}
62
+ ${options.strict ? '' : ' continue-on-error: true'}
63
+
64
+ `;
65
+
66
+ if (projectInfo.hasTypeScript) {
67
+ yaml += ` - name: Type check
68
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm type-check' : 'npm run type-check'}
69
+ ${options.strict ? '' : ' continue-on-error: true'}
70
+
71
+ `;
72
+ }
73
+
74
+ yaml += ` - name: Run tests
75
+ run: ${projectInfo.packageManager === 'pnpm' ? 'pnpm test' : 'npm test'}
76
+ continue-on-error: true
77
+ `;
78
+
79
+ return yaml;
80
+ }
81
+
82
+ function getInstallCommand(packageManager: ProjectInfo['packageManager']): string {
83
+ switch (packageManager) {
84
+ case 'pnpm':
85
+ return 'pnpm install --frozen-lockfile';
86
+ case 'yarn':
87
+ return 'yarn install --frozen-lockfile';
88
+ case 'npm':
89
+ default:
90
+ return 'npm ci';
91
+ }
92
+ }
93
+
94
+