create-restack-pattern 0.2.0 → 0.2.1

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 (2) hide show
  1. package/dist/index.js +48 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -54,14 +54,17 @@ Examples:
54
54
  console.log();
55
55
  p.intro(color.bgCyan(color.black(" create-restack-pattern ")));
56
56
  let projectName = process.argv[2];
57
+ let isCurrentDir = projectName === ".";
57
58
  if (!projectName || projectName.startsWith("-")) {
58
59
  const nameInput = await p.text({
59
60
  message: "What is your project named?",
60
- placeholder: "my-restack-app",
61
+ placeholder: "my-restack-app (or . for current directory)",
61
62
  defaultValue: "my-restack-app",
62
63
  validate: (value) => {
63
64
  if (!value)
64
65
  return "Project name cannot be empty";
66
+ if (value === ".")
67
+ return;
65
68
  if (!isValidProjectName(value)) {
66
69
  return "Project name may only contain letters, numbers, hyphens, and underscores";
67
70
  }
@@ -75,12 +78,41 @@ Examples:
75
78
  process.exit(0);
76
79
  }
77
80
  projectName = nameInput;
81
+ isCurrentDir = projectName === ".";
78
82
  }
79
- const targetDir = path.resolve(process.cwd(), projectName);
80
- if (existsSync(targetDir)) {
81
- p.cancel(color.red(`Error: Directory "${projectName}" already exists.`));
82
- process.exit(1);
83
+ let targetDir;
84
+ let displayProjectName;
85
+ if (isCurrentDir) {
86
+ targetDir = process.cwd();
87
+ displayProjectName = path.basename(targetDir);
88
+ const existingFiles = readdirSync(targetDir);
89
+ if (existingFiles.length > 0) {
90
+ const confirmOverwrite = await p.confirm({
91
+ message: `Current directory is not empty (${existingFiles.length} item(s) found). Continue and scaffold into this directory?`,
92
+ initialValue: false,
93
+ });
94
+ if (p.isCancel(confirmOverwrite) || !confirmOverwrite) {
95
+ p.cancel("Operation cancelled.");
96
+ process.exit(0);
97
+ }
98
+ }
83
99
  }
100
+ else {
101
+ if (!isValidProjectName(projectName)) {
102
+ p.cancel(color.red("Invalid project name. Use letters, numbers, hyphens, or underscores only."));
103
+ process.exit(1);
104
+ }
105
+ targetDir = path.resolve(process.cwd(), projectName);
106
+ displayProjectName = projectName;
107
+ if (existsSync(targetDir)) {
108
+ p.cancel(color.red(`Error: Directory "${projectName}" already exists.`));
109
+ process.exit(1);
110
+ }
111
+ }
112
+ const normalizedPkgName = displayProjectName
113
+ .toLowerCase()
114
+ .replace(/[^a-z0-9-_]/g, "-")
115
+ .replace(/^-+|-+$/g, "") || "restack-app";
84
116
  const database = (await p.select({
85
117
  message: "Select your database:",
86
118
  options: [
@@ -148,7 +180,7 @@ Examples:
148
180
  }
149
181
  const s = p.spinner();
150
182
  // 1. Scaffold files
151
- s.start(`Scaffolding ${projectName} (${database} + ${idStrategy}) ...`);
183
+ s.start(`Scaffolding ${displayProjectName} (${database} + ${idStrategy}) ...`);
152
184
  const baseDir = path.join(templateDir, "base");
153
185
  const overlaysDir = path.join(templateDir, "overlays");
154
186
  // Copy base template
@@ -172,7 +204,7 @@ Examples:
172
204
  // 2. Patch package.json files
173
205
  const rootPkgPath = path.join(targetDir, "package.json");
174
206
  const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
175
- rootPkg.name = projectName;
207
+ rootPkg.name = normalizedPkgName;
176
208
  if (packageManager !== "pnpm") {
177
209
  rootPkg.workspaces = ["frontend", "backend", "packages/*"];
178
210
  }
@@ -212,7 +244,7 @@ Examples:
212
244
  writeFileSync(frontendPkgPath, `${JSON.stringify(frontendPkg, null, 2)}\n`);
213
245
  }
214
246
  }
215
- s.stop(color.green(`Scaffolded ${projectName} files successfully!`));
247
+ s.stop(color.green(`Scaffolded ${displayProjectName} files successfully!`));
216
248
  // 3. Install dependencies
217
249
  if (isCommandAvailable(packageManager)) {
218
250
  s.start(`Installing dependencies using ${packageManager} ...`);
@@ -246,7 +278,9 @@ Examples:
246
278
  }
247
279
  // 5. Initialize git
248
280
  try {
249
- execSync("git init", { cwd: targetDir, stdio: "ignore" });
281
+ if (!existsSync(path.join(targetDir, ".git"))) {
282
+ execSync("git init", { cwd: targetDir, stdio: "ignore" });
283
+ }
250
284
  }
251
285
  catch {
252
286
  // Non-fatal
@@ -258,8 +292,11 @@ Examples:
258
292
  : `• For Backend:
259
293
  ${color.cyan("cp backend/.env.example backend/.env")}
260
294
  (SQLite database file will be created automatically at ${color.yellow("sqlite.db")})`;
261
- p.note(`1. Go to your project directory:
262
- ${color.cyan(`cd ${projectName}`)}
295
+ const cdStep = isCurrentDir
296
+ ? `1. You are already in the project directory!`
297
+ : `1. Go to your project directory:
298
+ ${color.cyan(`cd ${projectName}`)}`;
299
+ p.note(`${cdStep}
263
300
 
264
301
  2. Configure environment variables:
265
302
  ${dbConfigStep}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-restack-pattern",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Scaffold a new Next.js + Hono + Drizzle monorepo using the Restack Pattern (Semi-DDD) template.",
5
5
  "license": "MIT",
6
6
  "type": "module",