create-lumen 2.0.0-beta.3 → 2.0.0-beta.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lumen",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.0-beta.5",
4
4
  "description": "Scaffold a React + Vite or Next.js project with architecture choice: feature-based, type-based, or none.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cleanup.js CHANGED
@@ -21,6 +21,7 @@ export async function cleanupBoilerplate(projectPath, responses = {}) {
21
21
  await deleteIfExists(`${projectPath}/src/App.tsx`);
22
22
  await deleteIfExists(`${projectPath}/src/App.jsx`);
23
23
  await deleteIfExists(`${projectPath}/src/App.css`);
24
+ await deleteIfExists(`${projectPath}/src/shared/styles`);
24
25
 
25
26
  const isPagesRouter =
26
27
  responses?.framework?.variant === "pages-router" ||
@@ -34,7 +35,9 @@ export async function cleanupBoilerplate(projectPath, responses = {}) {
34
35
  await deleteIfExists(`${projectPath}/src/app/App.jsx`);
35
36
  await deleteIfExists(`${projectPath}/src/app/hooks`);
36
37
  await deleteIfExists(`${projectPath}/src/app/contexts`);
37
- await deleteIfExists(`${projectPath}/src/app/providers`);
38
+ if (responses?.stateManagement !== "redux") {
39
+ await deleteIfExists(`${projectPath}/src/app/providers`);
40
+ }
38
41
  }
39
42
  }
40
43
  }
package/src/cli-args.js CHANGED
@@ -299,6 +299,9 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
299
299
  styling: { type: "string" },
300
300
  "css-framework": { type: "string" },
301
301
  cssFramework: { type: "string" },
302
+ state: { type: "string", short: "s" },
303
+ "state-management": { type: "string" },
304
+ stateManagement: { type: "string" },
302
305
  ui: { type: "string", short: "u" },
303
306
  uiKit: { type: "string" },
304
307
  "ui-kit": { type: "string" },
@@ -348,6 +351,11 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
348
351
  values.cssFramework ||
349
352
  null;
350
353
  const uiKit = values.ui || values.uiKit || values["ui-kit"] || null;
354
+ let stateManagement = values.state || values["state-management"] || values.stateManagement || null;
355
+ if (stateManagement) {
356
+ stateManagement = stateManagement.trim().toLowerCase();
357
+ if (stateManagement === "rtk" || stateManagement === "reduxtoolkit") stateManagement = "redux";
358
+ }
351
359
  const testing = values.testing ? values.testing.trim().toLowerCase() : null;
352
360
  const linter = values.linter ? values.linter.trim().toLowerCase() : null;
353
361
  const formatter = values.formatter ? values.formatter.trim().toLowerCase() : null;
@@ -361,6 +369,7 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
361
369
  arch,
362
370
  language,
363
371
  cssFramework,
372
+ stateManagement,
364
373
  uiKit,
365
374
  bundler,
366
375
  adapter,
@@ -487,6 +496,7 @@ ${chalk.bold("OPTIONS")}
487
496
  ${chalk.yellow("-a, --arch")} <name> Architecture preset (feature-based, type-based, none)
488
497
  ${chalk.yellow("-l, --language")} <lang> Language (ts, js)
489
498
  ${chalk.yellow("-c, --css")} <framework> Styling engine (tailwind, none)
499
+ ${chalk.yellow("-s, --state")} <lib> State management (zustand, redux, none)
490
500
  ${chalk.yellow("-m, --manifest")} <path> Drive scaffolding from a lumen.config.json or inline JSON
491
501
  ${chalk.yellow("-t, --template")} <name> Scaffold using a preset (${Object.keys(PRESETS).join(", ")})
492
502
  ${chalk.yellow("-f, --framework")} <name> Target framework (react, next, react:vite, next:app-router, etc.)
package/src/css.js CHANGED
@@ -24,15 +24,26 @@ export async function setupCssFramework({
24
24
  // framework is "none"); type-based imports ./styles/globals.css (or
25
25
  // main.css). The chosen framework's styles land in the file the architecture
26
26
  // actually imports.
27
- const stylesDir =
28
- architecture === "feature-based"
29
- ? path.join(projectPath, "src", "shared", "styles")
30
- : path.join(projectPath, "src", "styles");
27
+ let stylesDir;
28
+ if (fw.name === "next") {
29
+ stylesDir =
30
+ fw.variant === "pages-router"
31
+ ? path.join(projectPath, "src", "styles")
32
+ : path.join(projectPath, "src", "app");
33
+ } else {
34
+ stylesDir =
35
+ architecture === "feature-based"
36
+ ? path.join(projectPath, "src", "shared", "styles")
37
+ : path.join(projectPath, "src", "styles");
38
+ }
31
39
 
32
40
  // Vanilla CSS gets a stylesheet named main.css; tailwind keeps
33
41
  // globals.css (its idiomatic name — it injects framework directives).
34
42
  const mainFileName = cssFramework === "none" ? "main.css" : "globals.css";
35
43
 
44
+ // Ensure the styles dir exists
45
+ await fsp.mkdir(stylesDir, { recursive: true });
46
+
36
47
  async function writeCss(content, fileName) {
37
48
  await fsp.writeFile(path.join(stylesDir, fileName), content, "utf8");
38
49
  }
@@ -34,6 +34,13 @@ export async function installAllDeps(responses, pkg, cwd) {
34
34
  for (const batch of devDepBatches) {
35
35
  await installDeps(pkg, true, batch, cwd);
36
36
  }
37
+
38
+ if (responses.database === "prisma") {
39
+ try {
40
+ const runner = pkg === "npm" ? "npx" : pkg;
41
+ await execa(runner, ["prisma", "generate"], { cwd, stdio: "pipe" });
42
+ } catch {}
43
+ }
37
44
  }
38
45
 
39
46
  // Pure dependency computation — the package list for a given matrix cell,
@@ -384,6 +384,7 @@ export function resolveFragments(responses = {}, templatesDir) {
384
384
  "db:push": "prisma db push",
385
385
  "db:seed": "prisma db seed",
386
386
  "db:studio": "prisma studio",
387
+ postinstall: "prisma generate",
387
388
  },
388
389
  action: async ({ projectPath, templatesDir: tDir }) => {
389
390
  const prismaTplDir = path.join(tDir, "conditional", "database", "prisma");
@@ -753,6 +754,9 @@ export function resolveFragments(responses = {}, templatesDir) {
753
754
  try {
754
755
  await fsp.rm(path.join(projectPath, "src", "app", "page.tsx"), { force: true });
755
756
  } catch {}
757
+ try {
758
+ await fsp.rm(path.join(projectPath, "src", "app", "page.module.css"), { force: true });
759
+ } catch {}
756
760
  // Adjust existing test file if it imported @/app/page before route groups was applied
757
761
  for (const testExt of ["tsx", "jsx", "ts", "js"]) {
758
762
  const testPath = path.join(projectPath, "src", "__tests__", `page.test.${testExt}`);
package/src/main.js CHANGED
@@ -54,6 +54,7 @@ export async function main(options = {}) {
54
54
  arch: archArg,
55
55
  language: languageArg,
56
56
  cssFramework: cssArg,
57
+ stateManagement: stateArg,
57
58
  uiKit: uiKitArg,
58
59
  database: databaseArg,
59
60
  databaseProvider: dbProviderArg,
@@ -118,6 +119,7 @@ export async function main(options = {}) {
118
119
  // Overlay explicit CLI flags if provided
119
120
  if (languageArg) responses.language = languageArg;
120
121
  if (cssArg) responses.cssFramework = cssArg;
122
+ if (stateArg) responses.stateManagement = stateArg;
121
123
  if (uiKitArg) responses.uiKit = uiKitArg;
122
124
  if (linterArg) responses.linter = linterArg;
123
125
  if (formatterArg) responses.formatter = formatterArg;
@@ -362,5 +364,5 @@ export async function main(options = {}) {
362
364
  );
363
365
 
364
366
  // 14. Offer dev server
365
- await handleDevServer(pkg, projectName, { isNonInteractive });
367
+ await handleDevServer(pkg, projectPath, { isNonInteractive, projectName });
366
368
  }
package/src/prompts.js CHANGED
@@ -548,6 +548,10 @@ export async function getUserInputs(
548
548
  {
549
549
  id: "stateManagement",
550
550
  message: "Which state management library do you want to use?",
551
+ skip: (ans) => ans.architecture === "none",
552
+ onSkip: (ans) => {
553
+ ans.stateManagement = "none";
554
+ },
551
555
  getOptions: () => [
552
556
  { label: "None", value: "none" },
553
557
  { label: "Redux Toolkit", value: "redux" },
@@ -1,14 +1,30 @@
1
1
  import { isCancel, select } from "@clack/prompts";
2
2
  import chalk from "chalk";
3
3
  import { execa } from "execa";
4
+ import path from "path";
4
5
 
5
- export async function handleDevServer(pkg, projectName, { isNonInteractive = false } = {}) {
6
- if (isNonInteractive || process.env.CI || !process.stdin.isTTY) {
7
- printNextSteps(projectName, pkg);
6
+ export async function handleDevServer(
7
+ pkg,
8
+ projectPathOrName,
9
+ {
10
+ isNonInteractive = false,
11
+ projectName = null,
12
+ selectFn = select,
13
+ execaFn = execa,
14
+ isTTY = process.stdin.isTTY,
15
+ } = {}
16
+ ) {
17
+ const targetDir = path.isAbsolute(projectPathOrName)
18
+ ? projectPathOrName
19
+ : path.resolve(process.cwd(), projectPathOrName);
20
+ const displayName = projectName || path.basename(projectPathOrName);
21
+
22
+ if (isNonInteractive || process.env.CI || !isTTY) {
23
+ printNextSteps(displayName, pkg);
8
24
  return;
9
25
  }
10
26
 
11
- const startDev = await select({
27
+ const startDev = await selectFn({
12
28
  message: "Start the development server?",
13
29
  options: [
14
30
  { label: "Yes", value: true },
@@ -18,22 +34,33 @@ export async function handleDevServer(pkg, projectName, { isNonInteractive = fal
18
34
  });
19
35
 
20
36
  if (isCancel(startDev)) {
21
- printNextSteps(projectName, pkg);
37
+ printNextSteps(displayName, pkg);
22
38
  return;
23
39
  }
24
40
 
25
41
  if (startDev) {
26
42
  console.log(chalk.green("\nStarting dev server...\n"));
27
- await execa(pkg, ["run", "dev"], { stdio: "inherit" });
43
+ try {
44
+ await execaFn(pkg, ["run", "dev"], { cwd: targetDir, stdio: "inherit" });
45
+ } catch (err) {
46
+ if (
47
+ err?.signal === "SIGINT" ||
48
+ err?.signal === "SIGTERM" ||
49
+ err?.exitCode === 130
50
+ ) {
51
+ return;
52
+ }
53
+ throw err;
54
+ }
28
55
  } else {
29
- printNextSteps(projectName, pkg);
56
+ printNextSteps(displayName, pkg);
30
57
  }
31
58
  }
32
59
 
33
- function printNextSteps(projectName, pkg) {
60
+ function printNextSteps(displayName, pkg) {
34
61
  console.log(chalk.bold("\nNext steps:"));
35
- if (projectName !== ".") {
36
- console.log(chalk.gray(` cd ${projectName}`));
62
+ if (displayName !== "." && displayName !== "") {
63
+ console.log(chalk.gray(` cd ${displayName}`));
37
64
  }
38
65
  console.log(chalk.gray(` ${pkg} run dev\n`));
39
66
  }
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { Provider } from "react-redux";
2
4
  import { store } from "@/shared/stores";
3
5
 
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import type { ReactNode } from "react";
2
4
  import { Provider } from "react-redux";
3
5
  import { store } from "@/shared/stores";
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { Provider } from "react-redux";
2
4
  import { store } from "@/store";
3
5
 
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import type { ReactNode } from "react";
2
4
  import { Provider } from "react-redux";
3
5
  import { store } from "@/store";