Skip to content

Commit 34740b3

Browse files
authored
Merge pull request #1 from ServiceStack/claude/create-npx-project-script-014KBKErgkQjXM1eXSndDaZi
Create NPX script for project template generation
2 parents b88ec2a + 9b4cafd commit 34740b3

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,30 @@ Create .NET and other projects from NetCoreTemplates GitHub repositories.
55
## Usage
66

77
```bash
8-
npx create-net <repo> <ProjectName>
8+
npx create-net <repo> [ProjectName]
99
```
1010

11+
If `ProjectName` is not specified, the script will use the current directory name and extract the template into the current directory (which must be empty).
12+
1113
### Examples
1214

13-
**Create a project from NetCoreTemplates organization:**
15+
**Create a project in a new directory:**
1416

1517
```bash
1618
npx create-net nextjs MyProject
1719
```
1820

19-
This downloads from: `https://github.com/NetCoreTemplates/nextjs`
21+
This downloads from: `https://github.com/NetCoreTemplates/nextjs` and creates a `MyProject` folder.
22+
23+
**Create a project in the current directory:**
24+
25+
```bash
26+
mkdir my-project
27+
cd my-project
28+
npx create-net nextjs
29+
```
30+
31+
This uses the current directory name (`my-project`) and extracts the template into the current directory.
2032

2133
**Create a project from a different organization:**
2234

@@ -29,8 +41,8 @@ This downloads from: `https://github.com/NetFrameworkTemplates/web-netfx`
2941
## What it does
3042

3143
1. **Downloads** the GitHub repository archive from the specified repository
32-
2. **Extracts** the archive into a folder named `<ProjectName>`
33-
3. **Replaces** all variations of `MyApp` with variations of your `<ProjectName>`:
44+
2. **Extracts** the archive into a folder named `<ProjectName>` (or current directory if no ProjectName specified)
45+
3. **Replaces** all variations of `MyApp` with variations of your `<ProjectName>` (or current directory name):
3446
- `My_App``Your_Project`
3547
- `My App``Your Project`
3648
- `my-app``your-project`

bin/create-net.js

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,28 @@ const AdmZip = require('adm-zip');
99
// Parse command line arguments
1010
const args = process.argv.slice(2);
1111

12-
if (args.length < 2) {
13-
console.error('Usage: npx create-net <repo> <ProjectName>');
14-
console.error('Example: npx create-net nextjs MyProject');
15-
console.error('Example: npx create-net NetFrameworkTemplates/web-netfx MyProject');
12+
if (args.length < 1) {
13+
console.error('Usage: npx create-net <repo> [ProjectName]');
14+
console.error('');
15+
console.error('If ProjectName is not specified, uses current directory name and extracts into current directory.');
16+
console.error('');
17+
console.error('Examples:');
18+
console.error(' npx create-net nextjs MyProject');
19+
console.error(' npx create-net NetFrameworkTemplates/web-netfx MyProject');
20+
console.error(' npx create-net nextjs (uses current directory name)');
1621
process.exit(1);
1722
}
1823

19-
const [repo, projectName] = args;
24+
const repo = args[0];
25+
let projectName = args[1];
26+
let extractToCurrentDir = false;
27+
28+
// If no project name specified, use current directory name
29+
if (!projectName) {
30+
projectName = path.basename(process.cwd());
31+
extractToCurrentDir = true;
32+
console.log(`No project name specified, using current directory name: "${projectName}"`);
33+
}
2034

2135
// Determine organization and repository
2236
let organization = 'NetCoreTemplates';
@@ -31,17 +45,32 @@ if (repo.includes('/')) {
3145
// Construct GitHub archive URL
3246
const archiveUrl = `https://github.com/${organization}/${repository}/archive/refs/heads/main.zip`;
3347
const tempZipPath = path.join(process.cwd(), 'temp-download.zip');
34-
const projectPath = path.join(process.cwd(), projectName);
48+
const projectPath = extractToCurrentDir ? process.cwd() : path.join(process.cwd(), projectName);
3549

3650
console.log(`Creating project "${projectName}" from ${organization}/${repository}...`);
3751
console.log(`Downloading from: ${archiveUrl}`);
3852

39-
// Check if project directory already exists
40-
if (fs.existsSync(projectPath)) {
53+
// Check if project directory already exists (only when creating a new directory)
54+
if (!extractToCurrentDir && fs.existsSync(projectPath)) {
4155
console.error(`Error: Directory "${projectName}" already exists.`);
4256
process.exit(1);
4357
}
4458

59+
// Check if current directory is not empty (when extracting to current dir)
60+
if (extractToCurrentDir) {
61+
const currentDirContents = fs.readdirSync(process.cwd()).filter(item =>
62+
item !== 'node_modules' &&
63+
item !== '.git' &&
64+
!item.startsWith('.')
65+
);
66+
67+
if (currentDirContents.length > 0) {
68+
console.error(`Error: Current directory is not empty. Please run this command in an empty directory.`);
69+
console.error(`Found: ${currentDirContents.join(', ')}`);
70+
process.exit(1);
71+
}
72+
}
73+
4574
// Function to download file from URL
4675
function downloadFile(url, destination) {
4776
return new Promise((resolve, reject) => {
@@ -220,12 +249,23 @@ async function main() {
220249
const tempExtractPath = path.join(process.cwd(), 'temp-extract');
221250
zip.extractAllTo(tempExtractPath, true);
222251

223-
// Move the extracted folder to the project name
224252
const extractedPath = path.join(tempExtractPath, rootFolder);
225-
fs.renameSync(extractedPath, projectPath);
253+
254+
if (extractToCurrentDir) {
255+
// Move contents of extracted folder to current directory
256+
const items = fs.readdirSync(extractedPath);
257+
for (const item of items) {
258+
const srcPath = path.join(extractedPath, item);
259+
const destPath = path.join(projectPath, item);
260+
fs.renameSync(srcPath, destPath);
261+
}
262+
} else {
263+
// Move the extracted folder to the project name
264+
fs.renameSync(extractedPath, projectPath);
265+
}
226266

227267
// Clean up temp extract directory
228-
fs.rmdirSync(tempExtractPath, { recursive: true });
268+
fs.rmSync(tempExtractPath, { recursive: true, force: true });
229269

230270
// Clean up temp zip file
231271
fs.unlinkSync(tempZipPath);
@@ -258,9 +298,15 @@ async function main() {
258298
runNpmInstall(projectPath);
259299

260300
console.log('\n✓ Project created successfully!');
261-
console.log(`\nNext steps:`);
262-
console.log(` cd ${projectName}`);
263-
console.log(` npm start (or appropriate command for your template)`);
301+
302+
if (!extractToCurrentDir) {
303+
console.log(`\nNext steps:`);
304+
console.log(` cd ${projectName}`);
305+
console.log(` npm start (or appropriate command for your template)`);
306+
} else {
307+
console.log(`\nNext steps:`);
308+
console.log(` npm start (or appropriate command for your template)`);
309+
}
264310

265311
} catch (err) {
266312
console.error('Error creating project:', err.message);

0 commit comments

Comments
 (0)