Skip to content

Commit 260dd6f

Browse files
committed
Polish CLI flow and release prep
1 parent 9790c6a commit 260dd6f

File tree

20 files changed

+337
-371
lines changed

20 files changed

+337
-371
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* text=auto eol=lf
2+

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
test:
16+
runs-on: ${{ matrix.os }}
17+
timeout-minutes: 10
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
os: [ubuntu-latest, windows-latest, macos-latest]
22+
node-version: [20, 22]
23+
24+
steps:
25+
- name: Check out repository
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: ${{ matrix.node-version }}
32+
cache: npm
33+
34+
- name: Install dependencies
35+
run: npm ci
36+
37+
- name: Run tests
38+
run: npm test

.gitignore

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
1-
# dependencies
21
node_modules/
3-
4-
# logs
52
*.log
63
npm-debug.log*
74
yarn-debug.log*
8-
pnpm-debug.log*
9-
10-
# OS files
115
.DS_Store
126
Thumbs.db
13-
14-
# environment variables
157
.env
168
.env.local
179
.env.*.local
18-
19-
# build output (for TS templates if ever used internally)
2010
dist/
21-
22-
# editor files
2311
.vscode/
2412
.idea/
25-
26-
# coverage / test
2713
coverage/
28-
29-
# temp files
30-
*.tmp
31-
*.temp

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2026 codehassoul
3+
Copyright (c) 2026
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,103 @@
1-
![npm version](https://img.shields.io/npm/v/setup-node-api)
2-
![downloads](https://img.shields.io/npm/dm/setup-node-api)
1+
[![npm version](https://img.shields.io/npm/v/setup-node-api)](https://www.npmjs.com/package/setup-node-api)
2+
[![npm downloads](https://img.shields.io/npm/dm/setup-node-api)](https://www.npmjs.com/package/setup-node-api)
3+
[![CI](https://github.com/codehassoul/setup-node-api/actions/workflows/ci.yml/badge.svg)](https://github.com/codehassoul/setup-node-api/actions/workflows/ci.yml)
34

45
# setup-node-api
56

6-
A minimal CLI for scaffolding Node.js + Express APIs.
7+
`setup-node-api` scaffolds a minimal Node.js + Express API with sensible defaults.
78

8-
Opinionated, simple, and focused on developer experience.
9+
Node.js 20.12.0 or newer is required.
910

10-
---
11+
## Features
12+
13+
- Scaffold a ready-to-run Express API
14+
- Choose JavaScript or TypeScript
15+
- Use prompts interactively or pass CLI flags
16+
- Validate project names before generation
17+
- Avoid overwriting existing folders without confirmation
18+
- Optionally skip dependency installation
1119

12-
## Quick Start
20+
## Quick start
1321

1422
```bash
1523
npx setup-node-api my-api
1624
```
1725

18-
---
26+
Create a TypeScript project:
1927

20-
## Features
28+
```bash
29+
npx setup-node-api my-api --typescript
30+
```
2131

22-
* Fast API scaffolding
23-
* JavaScript and TypeScript support
24-
* Interactive prompts + CLI flags
25-
* Safe project creation
26-
* Clean project structure
32+
Skip package installation:
2733

28-
---
34+
```bash
35+
npx setup-node-api my-api --no-install
36+
```
2937

30-
## Usage
38+
Set a custom port:
3139

3240
```bash
33-
setup-node-api <project-name>
41+
npx setup-node-api my-api --port 8080
3442
```
3543

36-
### Options
44+
## CLI usage
3745

3846
```bash
39-
--typescript
40-
--no-install
41-
--port <number>
47+
setup-node-api [project-name] [options]
4248
```
4349

44-
---
50+
### Options
4551

46-
## Example
52+
| Option | Description |
53+
| --- | --- |
54+
| `--typescript` | Generate the TypeScript template |
55+
| `--no-install` | Skip dependency installation |
56+
| `--port <number>` | Write a custom `PORT` value to `.env` |
57+
| `-h, --help` | Show help |
58+
| `-V, --version` | Show the installed CLI version |
4759

48-
```bash
49-
npx setup-node-api my-api --typescript
50-
```
60+
If you omit some options, the CLI prompts for them in an interactive terminal.
5161

52-
---
62+
## Generated project
5363

54-
## Generated Project
64+
JavaScript template:
5565

5666
```text
5767
my-api/
58-
|-- src/
59-
| `-- app.js / app.ts
60-
|-- package.json
61-
`-- .env
68+
|-- .env
69+
|-- package.json
70+
`-- src/
71+
`-- app.js
6272
```
6373

64-
---
74+
TypeScript template:
6575

66-
## Architecture
76+
```text
77+
my-api/
78+
|-- .env
79+
|-- package.json
80+
|-- tsconfig.json
81+
`-- src/
82+
`-- app.ts
83+
```
84+
85+
## Development
6786

68-
* CLI layer (Commander)
69-
* Core orchestration layer
70-
* Services (template, install, filesystem)
71-
* Prompt system + validation
87+
```bash
88+
npm install
89+
npm test
90+
```
7291

73-
---
92+
## CI
7493

75-
## Roadmap
94+
GitHub Actions runs the test suite on Node.js 20 and 22 across Linux, Windows, and macOS for pushes to `main` and pull requests.
7695

77-
* Command-based CLI (`create`, `add`, `generate`)
78-
* Config file support
79-
* Plugin system
80-
* AI-assisted scaffolding
96+
## Notes
8197

82-
---
98+
- In a non-interactive environment, provide the project name as an argument.
99+
- If the target folder already exists, the CLI stops unless you explicitly confirm overwrite in an interactive terminal.
100+
- The generated project package name is automatically set to the selected folder name.
83101

84102
## License
85103

assets/demo.png

-35.4 KB
Binary file not shown.

bin/cli.js

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env node
22

33
const path = require("path");
4+
const chalk = require("chalk");
45
const { Command } = require("commander");
56
const packageJson = require("../package.json");
67
const { createApp } = require("../src/core");
@@ -11,9 +12,28 @@ const { handleExistingDir } = require("../src/core/services/fileService");
1112

1213
const program = new Command();
1314

15+
function exitWithError(message, exitCode = 1) {
16+
console.log(chalk.red(`Error: ${message}`));
17+
process.exit(exitCode);
18+
}
19+
20+
function parsePort(portValue) {
21+
if (portValue === undefined) {
22+
return undefined;
23+
}
24+
25+
const parsedPort = Number.parseInt(portValue, 10);
26+
27+
if (!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65535) {
28+
throw new Error("Port must be an integer between 1 and 65535.");
29+
}
30+
31+
return parsedPort;
32+
}
33+
1434
program
1535
.name("setup-node-api")
16-
.description("CLI to create a Node.js Express API")
36+
.description("Scaffold a Node.js + Express API")
1737
.version(packageJson.version);
1838

1939
program
@@ -25,45 +45,32 @@ program
2545
try {
2646
if (projectName !== undefined) {
2747
validateProjectName(projectName);
28-
29-
const projectPathCheck = path.join(process.cwd(), projectName);
30-
31-
if (projectPathCheck === process.cwd()) {
32-
console.log("Error: cannot use current directory as project name.");
33-
process.exit(1);
34-
}
3548
}
3649
} catch (err) {
37-
console.log("Error:", err.message);
38-
process.exit(1);
50+
exitWithError(err.message);
3951
}
4052

41-
const parsedPort =
42-
options.port === undefined ? undefined : Number.parseInt(options.port, 10);
53+
let parsedPort;
4354

44-
if (
45-
options.port !== undefined &&
46-
(!Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65535)
47-
) {
48-
console.log("Error: port must be an integer between 1 and 65535.");
49-
process.exit(1);
55+
try {
56+
parsedPort = parsePort(options.port);
57+
} catch (err) {
58+
exitWithError(err.message);
5059
}
5160

5261
const projectPath = projectName
5362
? path.join(process.cwd(), projectName)
5463
: null;
5564

5665
if (projectPath && projectPath === process.cwd()) {
57-
console.log("Error: refusing to overwrite the current directory.");
58-
process.exit(1);
66+
exitWithError("Refusing to overwrite the current directory.");
5967
}
6068

6169
if (projectPath) {
6270
try {
6371
await handleExistingDir(projectPath);
6472
} catch (err) {
65-
console.log("Warning:", err.message);
66-
process.exit(0);
73+
exitWithError(err.message);
6774
}
6875
}
6976

@@ -74,8 +81,7 @@ program
7481
port: parsedPort,
7582
});
7683
} catch (err) {
77-
console.log("Error:", err.message);
78-
process.exit(1);
84+
exitWithError(err.message);
7985
}
8086
});
8187

0 commit comments

Comments
 (0)