@ghentcdh/create-crouton 0.0.1-alpha.26 → 0.0.1-alpha.28

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 (33) hide show
  1. package/dist/index.js +120 -35
  2. package/dist/index.js.map +1 -1
  3. package/dist/lib/index.js +20 -2
  4. package/dist/lib/index.js.map +1 -1
  5. package/dist/templates/nx/root/eslint.config.mjs.tmpl +45 -0
  6. package/dist/templates/nx/root/nx.json.tmpl +2 -1
  7. package/dist/templates/nx/root/package.json.tmpl +15 -2
  8. package/dist/templates/nx/root/pnpm-workspace.yaml.tmpl +18 -2
  9. package/dist/templates/nx/root/tsconfig.base.json.tmpl +4 -1
  10. package/dist/templates/nx/workspace/apps/backend/eslint.config.mjs.tmpl +3 -0
  11. package/dist/templates/nx/workspace/apps/backend/nodemon.json.tmpl +6 -0
  12. package/dist/templates/nx/workspace/apps/backend/package.json.tmpl +5 -5
  13. package/dist/templates/nx/workspace/apps/backend/project.json.tmpl +20 -2
  14. package/dist/templates/nx/workspace/apps/backend/src/app/app.module.ts.tmpl +1 -0
  15. package/dist/templates/nx/workspace/apps/backend/tsconfig.json.tmpl +2 -2
  16. package/dist/templates/nx/workspace/apps/backend/tsup.config.ts.tmpl +31 -0
  17. package/dist/templates/nx/workspace/apps/frontend/eslint.config.mjs.tmpl +3 -0
  18. package/dist/templates/nx/workspace/apps/frontend/package.json.tmpl +3 -0
  19. package/dist/templates/nx/workspace/apps/frontend/project.json.tmpl +1 -1
  20. package/dist/templates/nx/workspace/apps/frontend/src/App.vue.tmpl +1 -4
  21. package/dist/templates/nx/workspace/apps/frontend/src/main.ts.tmpl +22 -1
  22. package/dist/templates/nx/workspace/apps/frontend/src/style.css.tmpl +38 -0
  23. package/dist/templates/nx/workspace/apps/frontend/tsconfig.json.tmpl +1 -1
  24. package/dist/templates/nx/workspace/apps/frontend/vite.config.ts.tmpl +3 -1
  25. package/dist/templates/nx/workspace/generated/default/client/package.json.tmpl +10 -0
  26. package/dist/templates/nx/workspace/generated/default/types/package.json.tmpl +14 -0
  27. package/dist/templates/regular/.npmrc.tmpl +5 -0
  28. package/dist/templates/regular/package.json.tmpl +1 -0
  29. package/dist/templates/regular/src/app.module.ts.tmpl +1 -0
  30. package/dist/templates/regular/tsconfig.json.tmpl +2 -1
  31. package/package.json +6 -3
  32. package/dist/templates/nx/workspace/apps/backend/nest-cli.json.tmpl +0 -8
  33. package/dist/templates/nx/workspace/generated/types/package.json.tmpl +0 -6
package/dist/index.js CHANGED
@@ -19069,7 +19069,7 @@ var SidebarGroupSchema = zod_default.object({
19069
19069
  /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
19070
19070
  label: zod_default.string().optional(),
19071
19071
  /** Controls the order of this group among top-level sidebar items. */
19072
- position: zod_default.string().optional()
19072
+ position: zod_default.number().optional()
19073
19073
  });
19074
19074
  var SidebarSchema = zod_default.object({
19075
19075
  hide: zod_default.boolean().default(false),
@@ -19243,7 +19243,9 @@ var RulesetSchema = external_exports.object({
19243
19243
  showRelationsInForm: external_exports.boolean().default(true),
19244
19244
  enumValueLabel: external_exports.boolean().default(true),
19245
19245
  sharedEnums: external_exports.boolean().default(true),
19246
- defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
19246
+ defaultOperations: JsonOperationsSchema.default(
19247
+ JsonOperationsSchema.parse({})
19248
+ )
19247
19249
  });
19248
19250
  var CroutonConfigSchema = external_exports.object({
19249
19251
  /**
@@ -19262,7 +19264,7 @@ var CroutonConfigSchema = external_exports.object({
19262
19264
  */
19263
19265
  schemaExportName: external_exports.string().default("{Model}WithRelationsSchema"),
19264
19266
  /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
19265
- enumsFile: external_exports.string().default("croutons.enums.json"),
19267
+ enumsFile: external_exports.string().default("crouton.enums.json"),
19266
19268
  /** Optional overrides of the default visibility ruleset. */
19267
19269
  rules: RulesetSchema.default(RulesetSchema.parse({})),
19268
19270
  /**
@@ -19334,9 +19336,10 @@ var buildDatasourceFiles = (opts) => {
19334
19336
  urlEnv: opts.urlEnv,
19335
19337
  generatedTypesImport: opts.generatedTypesImport,
19336
19338
  zodOutput,
19339
+ clientOutput,
19337
19340
  prismaConfig
19338
19341
  };
19339
- const clientImport = relImport(dsDir, clientOutput);
19342
+ const clientImport = opts.generatedClientImport ?? relImport(dsDir, clientOutput);
19340
19343
  const indexTs = `import { PrismaClient } from '${clientImport}';
19341
19344
  import { PrismaPg } from '@prisma/adapter-pg';
19342
19345
 
@@ -19372,14 +19375,17 @@ datasource db {
19372
19375
  // url is provided by ${prismaConfig} (Prisma 7 forbids \`url\` here)
19373
19376
  }
19374
19377
  `;
19378
+ const configDir = dirname4(prismaConfig);
19379
+ const relSchema = relImport(configDir, prismaSchema);
19380
+ const relMigrations = relImport(configDir, migrationsDir);
19375
19381
  const prismaConfigTs = `// Generated by \`crouton create-datasource\`.
19376
19382
  import 'dotenv/config';
19377
19383
  import { defineConfig, env } from 'prisma/config';
19378
19384
 
19379
19385
  export default defineConfig({
19380
- schema: '${prismaSchema}',
19386
+ schema: '${relSchema}',
19381
19387
  migrations: {
19382
- path: '${migrationsDir}',
19388
+ path: '${relMigrations}',
19383
19389
  },
19384
19390
  datasource: {
19385
19391
  url: env('${opts.urlEnv}'),
@@ -19433,7 +19439,24 @@ var writeFiles = async (files, opts = {}) => {
19433
19439
  var loadTemplate = async (templateDir, relativePath) => readFile4(`${templateDir}/${relativePath}`, "utf-8");
19434
19440
 
19435
19441
  // src/lib/pm.ts
19436
- import { spawn } from "child_process";
19442
+ import { execSync, spawn } from "child_process";
19443
+ var MIN_PNPM_MAJOR = 11;
19444
+ var checkPnpmVersion = () => {
19445
+ let raw;
19446
+ try {
19447
+ raw = execSync("pnpm --version", { stdio: "pipe" }).toString().trim();
19448
+ } catch {
19449
+ throw new Error("pnpm is not installed. Install it with: npm i -g pnpm@latest");
19450
+ }
19451
+ const major = parseInt(raw.split(".")[0], 10);
19452
+ if (isNaN(major) || major < MIN_PNPM_MAJOR) {
19453
+ throw new Error(
19454
+ `pnpm ${raw} detected, but version ${MIN_PNPM_MAJOR}+ is required.
19455
+ Upgrade with: npm i -g pnpm@latest`
19456
+ );
19457
+ }
19458
+ return raw;
19459
+ };
19437
19460
  var installDeps = (pm, cwd) => new Promise((resolve3, reject) => {
19438
19461
  const child = spawn(pm, ["install"], { cwd, stdio: "inherit" });
19439
19462
  child.on(
@@ -19469,7 +19492,7 @@ var render = (template, tokens) => {
19469
19492
  };
19470
19493
 
19471
19494
  // src/runner.ts
19472
- import { execSync } from "child_process";
19495
+ import { execSync as execSync2 } from "child_process";
19473
19496
  import { existsSync } from "fs";
19474
19497
  import { readdir as readdir4 } from "fs/promises";
19475
19498
  import { resolve as resolve2 } from "path";
@@ -19489,7 +19512,9 @@ var runCreate = async (name, opts) => {
19489
19512
  if (existsSync(targetDir) && !opts.force) {
19490
19513
  const entries = await readdir4(targetDir);
19491
19514
  if (entries.length > 0) {
19492
- M2.error(`Directory "${name}" already exists and is not empty. Use --force to overwrite.`);
19515
+ M2.error(
19516
+ `Directory "${name}" already exists and is not empty. Use --force to overwrite.`
19517
+ );
19493
19518
  throw new CancelledError();
19494
19519
  }
19495
19520
  }
@@ -19497,6 +19522,10 @@ var runCreate = async (name, opts) => {
19497
19522
  const frontend = await resolveFrontend(opts, layout);
19498
19523
  const prefix = layout === "nx" ? await resolvePrefix(opts) : void 0;
19499
19524
  const pm = await resolvePm(opts);
19525
+ if (pm === "pnpm") {
19526
+ const pnpmVersion = checkPnpmVersion();
19527
+ M2.info(`Using pnpm ${pnpmVersion}`);
19528
+ }
19500
19529
  const dbUrl = await resolveDbUrl(opts);
19501
19530
  const dbName = name.replace(/[^a-zA-Z0-9]/g, "_");
19502
19531
  const tokens = {
@@ -19516,12 +19545,16 @@ var runCreate = async (name, opts) => {
19516
19545
  tokens["prefix"] = prefix;
19517
19546
  tokens["appsRoot"] = `${prefix}/apps`;
19518
19547
  tokens["schemaPath"] = "../../../node_modules/nx/schemas/project-schema.json";
19519
- tokens["generatedTypesPath"] = `${prefix}/generated/types/src`;
19548
+ tokens["tsconfigBase"] = "../../../tsconfig.base.json";
19549
+ tokens["generatedTypesPath"] = `${prefix}/generated/default/types/src`;
19550
+ tokens["generatedClientPath"] = `${prefix}/generated/default/client`;
19520
19551
  } else {
19521
19552
  tokens["noPrefix"] = "true";
19522
19553
  tokens["appsRoot"] = "apps";
19523
19554
  tokens["schemaPath"] = "../../node_modules/nx/schemas/project-schema.json";
19524
- tokens["generatedTypesPath"] = "generated/types/src";
19555
+ tokens["tsconfigBase"] = "../../tsconfig.base.json";
19556
+ tokens["generatedTypesPath"] = "generated/default/types/src";
19557
+ tokens["generatedClientPath"] = "generated/default/client";
19525
19558
  }
19526
19559
  }
19527
19560
  if (frontend) {
@@ -19531,51 +19564,89 @@ var runCreate = async (name, opts) => {
19531
19564
  const skipPaths = !frontend ? ["apps/frontend"] : [];
19532
19565
  if (layout === "nx") {
19533
19566
  const rootTemplateDir = resolve2(templateRoot, "nx", "root");
19534
- const rootFiles = await loadAndRenderTemplates(rootTemplateDir, "", tokens, targetDir);
19567
+ const rootFiles = await loadAndRenderTemplates(
19568
+ rootTemplateDir,
19569
+ "",
19570
+ tokens,
19571
+ targetDir
19572
+ );
19535
19573
  const files = [...rootFiles];
19536
19574
  const workspaceTemplateDir = resolve2(templateRoot, "nx", "workspace");
19537
19575
  const workspaceTarget = prefix ? resolve2(targetDir, prefix) : targetDir;
19538
- const workspaceFiles = await loadAndRenderTemplates(workspaceTemplateDir, "", tokens, workspaceTarget, skipPaths);
19576
+ const workspaceFiles = await loadAndRenderTemplates(
19577
+ workspaceTemplateDir,
19578
+ "",
19579
+ tokens,
19580
+ workspaceTarget,
19581
+ skipPaths
19582
+ );
19539
19583
  files.push(...workspaceFiles);
19540
19584
  if (opts.docker !== false) {
19541
19585
  const dockerDir = resolve2(templateRoot, "docker");
19542
- const dockerFiles = await loadAndRenderTemplates(dockerDir, "", tokens, targetDir);
19586
+ const dockerFiles = await loadAndRenderTemplates(
19587
+ dockerDir,
19588
+ "",
19589
+ tokens,
19590
+ targetDir
19591
+ );
19543
19592
  files.push(...dockerFiles);
19544
19593
  }
19545
19594
  const dataSourcesDir = "apps/backend/src/app/data-sources";
19546
- const generatedImport = `@${name}/generated/default`;
19595
+ const generatedImport = `@${name}/generated-default-types`;
19596
+ const generatedClientImport = `@${name}/generated-default-client`;
19547
19597
  const { files: dsFiles } = buildDatasourceFiles({
19548
19598
  name: "default",
19549
19599
  dataSourcesDir,
19550
19600
  urlEnv: "DATABASE_URL",
19551
19601
  generatedTypesImport: generatedImport,
19602
+ generatedClientImport,
19552
19603
  type: "postgres",
19553
- default: true
19604
+ default: true,
19605
+ zodOutput: "generated/default/types/src",
19606
+ clientOutput: "generated/default/client"
19554
19607
  });
19555
19608
  for (const f of dsFiles) {
19556
- files.push({ path: resolve2(workspaceTarget, f.path), contents: f.contents });
19609
+ files.push({
19610
+ path: resolve2(workspaceTarget, f.path),
19611
+ contents: f.contents
19612
+ });
19557
19613
  }
19558
19614
  const written = await writeFiles(files, { force: opts.force });
19559
19615
  M2.success(`Wrote ${written} file(s) to ${import_picocolors3.default.cyan(name)}/`);
19560
19616
  await postScaffold(opts, targetDir, pm, dbUrl, prefix);
19561
19617
  } else {
19562
19618
  const templateDir = resolve2(templateRoot, "regular");
19563
- const files = await loadAndRenderTemplates(templateDir, "", tokens, targetDir, skipPaths);
19619
+ const files = await loadAndRenderTemplates(
19620
+ templateDir,
19621
+ "",
19622
+ tokens,
19623
+ targetDir,
19624
+ skipPaths
19625
+ );
19564
19626
  if (opts.docker !== false) {
19565
19627
  const dockerTokens = { ...tokens, regular: "true" };
19566
19628
  const dockerDir = resolve2(templateRoot, "docker");
19567
- const dockerFiles = await loadAndRenderTemplates(dockerDir, "", dockerTokens, targetDir);
19629
+ const dockerFiles = await loadAndRenderTemplates(
19630
+ dockerDir,
19631
+ "",
19632
+ dockerTokens,
19633
+ targetDir
19634
+ );
19568
19635
  files.push(...dockerFiles);
19569
19636
  }
19570
19637
  const dataSourcesDir = "src/data-sources";
19571
- const generatedImport = "@app/generated/default";
19638
+ const generatedImport = "@app/generated/default/types";
19639
+ const generatedClientImport = "@app/generated/default/client";
19572
19640
  const { files: dsFiles } = buildDatasourceFiles({
19573
19641
  name: "default",
19574
19642
  dataSourcesDir,
19575
19643
  urlEnv: "DATABASE_URL",
19576
19644
  generatedTypesImport: generatedImport,
19645
+ generatedClientImport,
19577
19646
  type: "postgres",
19578
- default: true
19647
+ default: true,
19648
+ zodOutput: "generated/default/types/src",
19649
+ clientOutput: "generated/default/client"
19579
19650
  });
19580
19651
  for (const f of dsFiles) {
19581
19652
  files.push({ path: resolve2(targetDir, f.path), contents: f.contents });
@@ -19585,11 +19656,12 @@ var runCreate = async (name, opts) => {
19585
19656
  await postScaffold(opts, targetDir, pm, dbUrl);
19586
19657
  }
19587
19658
  const pmRun = pm === "npm" ? "npm run" : pm;
19659
+ const prefixFlag = prefix ? ` --prefix ${prefix}` : "";
19588
19660
  Me(
19589
19661
  [
19590
19662
  opts.docker !== false ? "docker compose up -d # start postgres" : null,
19591
19663
  `${pmRun} prisma:migrate # create initial migration`,
19592
- "crouton update resources # generate resource CRUD",
19664
+ `crouton update resources${prefixFlag} # generate resource CRUD`,
19593
19665
  `${pmRun} dev # start dev server`
19594
19666
  ].filter(Boolean).join("\n"),
19595
19667
  "Next steps"
@@ -19608,7 +19680,7 @@ var postScaffold = async (opts, targetDir, pm, dbUrl, prefix) => {
19608
19680
  const s = Y2();
19609
19681
  s.start("Initializing git repository");
19610
19682
  try {
19611
- execSync('git init && git add -A && git commit -m "Initial commit"', {
19683
+ execSync2('git init && git add -A && git commit -m "Initial commit"', {
19612
19684
  cwd: targetDir,
19613
19685
  stdio: "pipe"
19614
19686
  });
@@ -19629,22 +19701,26 @@ var postScaffold = async (opts, targetDir, pm, dbUrl, prefix) => {
19629
19701
  if (dbUrl) {
19630
19702
  try {
19631
19703
  const s2 = Y2();
19632
- s2.start("Running prisma generate");
19633
- const prismaConfigPath = prefix ? `${prefix}/prisma/default/prisma.config.ts` : "prisma/default/prisma.config.ts";
19634
- execSync(`npx prisma generate --config ${prismaConfigPath}`, {
19635
- cwd: targetDir,
19636
- stdio: "pipe"
19704
+ s2.start("Running crouton update resources");
19705
+ const croutonCwd = prefix ? resolve2(targetDir, prefix) : targetDir;
19706
+ execSync2("npx crouton update resources --yes", {
19707
+ cwd: croutonCwd,
19708
+ stdio: "pipe",
19709
+ env: { ...process.env, DATABASE_URL: dbUrl }
19637
19710
  });
19638
- s2.stop("Prisma client generated");
19639
- } catch {
19640
- M2.warn("prisma generate failed \u2014 run it manually after setting up your database.");
19711
+ s2.stop("Resources updated");
19712
+ } catch (err) {
19713
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr).trim() : "";
19714
+ M2.warn(
19715
+ "crouton update resources failed \u2014 run it manually after setting up your database." + (stderr ? `
19716
+ ${import_picocolors3.default.dim(stderr)}` : "")
19717
+ );
19641
19718
  }
19642
- } else {
19643
- M2.info("Skipping prisma generate \u2014 no database URL provided.");
19644
19719
  }
19645
19720
  }
19646
19721
  };
19647
19722
  var resolveLayout = async (opts) => {
19723
+ if (opts.prefix) return "nx";
19648
19724
  if (opts.yes) return opts.nx ? "nx" : "regular";
19649
19725
  if (opts.nx) return "nx";
19650
19726
  const layout = assertNotCancel(
@@ -19652,7 +19728,10 @@ var resolveLayout = async (opts) => {
19652
19728
  message: "Project layout",
19653
19729
  options: [
19654
19730
  { value: "regular", label: "Regular (single NestJS app)" },
19655
- { value: "nx", label: "Nx monorepo (backend + frontend + shared libs)" }
19731
+ {
19732
+ value: "nx",
19733
+ label: "Nx monorepo (backend + frontend + shared libs)"
19734
+ }
19656
19735
  ]
19657
19736
  })
19658
19737
  );
@@ -19717,7 +19796,13 @@ var loadAndRenderTemplates = async (templateDir, subPath, tokens, targetDir, ski
19717
19796
  const relPath = subPath ? `${subPath}/${entry.name}` : entry.name;
19718
19797
  if (skipPaths.some((sp) => relPath.startsWith(sp))) continue;
19719
19798
  if (entry.isDirectory()) {
19720
- const nested = await loadAndRenderTemplates(templateDir, relPath, tokens, targetDir, skipPaths);
19799
+ const nested = await loadAndRenderTemplates(
19800
+ templateDir,
19801
+ relPath,
19802
+ tokens,
19803
+ targetDir,
19804
+ skipPaths
19805
+ );
19721
19806
  files.push(...nested);
19722
19807
  } else if (entry.name.endsWith(".tmpl")) {
19723
19808
  const raw = await loadTemplate(templateDir, relPath);