Add smart init flow for existing projects#17
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR adds a new initialization workflow that enables Prisma setup in existing projects. It introduces an init command that is intelligently invoked from the create command when a package.json exists, alongside new init templates, template rendering, and infrastructure updates to support singleton path configuration. Changes
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/tasks/setup-prisma.ts (1)
57-67: 🧹 Nitpick | 🔵 TrivialCentralize the singleton path rules.
Lines 57-67 and 452-460 now encode the same framework lookup order in two places. That list is already on different relative bases (
packages/db/src/client.tsvssrc/client.tsunderprismaProjectDir), so the next template addition can easily update validation without updating resolution, or vice versa.♻️ Suggested consolidation
+const prismaSingletonCandidates = [ + "src/lib/prisma.ts", + "src/lib/prisma.server.ts", + "src/lib/server/prisma.ts", + "server/utils/prisma.ts", +] as const; + +async function findFirstExistingPath( + baseDir: string, + candidates: readonly string[] +): Promise<string | undefined> { + for (const relativePath of candidates) { + const absolutePath = path.join(baseDir, relativePath); + if (await fs.pathExists(absolutePath)) { + return absolutePath; + } + } +} + const requiredPrismaFileGroups = [ ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"], ["prisma/seed.ts", "packages/db/prisma/seed.ts"], ["prisma.config.ts", "packages/db/prisma.config.ts"], [ - "src/lib/prisma.ts", - "src/lib/prisma.server.ts", - "src/lib/server/prisma.ts", - "server/utils/prisma.ts", + ...prismaSingletonCandidates, "packages/db/src/client.ts", ], ] as const; ... - const singletonPath = (await fs.pathExists(path.join(prismaProjectDir, "src/lib/prisma.ts"))) - ? path.join(prismaProjectDir, "src/lib/prisma.ts") - : (await fs.pathExists(path.join(prismaProjectDir, "src/lib/prisma.server.ts"))) - ? path.join(prismaProjectDir, "src/lib/prisma.server.ts") - : (await fs.pathExists(path.join(prismaProjectDir, "src/lib/server/prisma.ts"))) - ? path.join(prismaProjectDir, "src/lib/server/prisma.ts") - : (await fs.pathExists(path.join(prismaProjectDir, "server/utils/prisma.ts"))) - ? path.join(prismaProjectDir, "server/utils/prisma.ts") - : path.join(prismaProjectDir, "src/client.ts"); + const singletonPath = + (await findFirstExistingPath(prismaProjectDir, [ + ...prismaSingletonCandidates, + "src/client.ts", + ])) ?? path.join(prismaProjectDir, "src/client.ts");Also applies to: 452-460
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 74dafb57-2ebb-46bf-ac8d-c3beec11fbf1
📒 Files selected for processing (24)
README.mdsrc/cli.tssrc/commands/create.tssrc/commands/init.tssrc/index.tssrc/tasks/setup-prisma.tssrc/templates/render-init-template.tssrc/types.tstemplates/create/tanstack-start/.gitignoretemplates/create/tanstack-start/.yarnrc.yml.hbstemplates/create/tanstack-start/README.md.hbstemplates/create/tanstack-start/deno.json.hbstemplates/create/tanstack-start/package.json.hbstemplates/create/tanstack-start/prisma.config.tstemplates/create/tanstack-start/prisma/schema.prisma.hbstemplates/create/tanstack-start/prisma/seed.ts.hbstemplates/create/tanstack-start/src/lib/prisma.server.ts.hbstemplates/create/tanstack-start/src/routeTree.gen.tstemplates/create/tanstack-start/src/router.tsxtemplates/create/tanstack-start/src/routes/__root.tsx.hbstemplates/create/tanstack-start/src/routes/index.tsx.hbstemplates/create/tanstack-start/src/styles.csstemplates/create/tanstack-start/tsconfig.jsontemplates/create/tanstack-start/vite.config.ts
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/commands/create.ts (1)
167-174:⚠️ Potential issue | 🟠 MajorOnly enable smart-init for the default entrypoint.
Lines 167-174 apply the init heuristic inside
runCreateCommand()itself, so the explicitcreate-prisma createpath will still switch into init whenever the current directory has apackage.json. That breaks the “create is the explicit scaffold flow” contract, and create-only flags like--force/--skillscan get dropped once control moves torunInitCommand().💡 Suggested direction
-export async function runCreateCommand(rawInput: CreateCommandInput = {}): Promise<void> { +export async function runCreateCommand( + rawInput: CreateCommandInput = {}, + options: { allowSmartInit?: boolean } = {} +): Promise<void> { try { const input = CreateCommandInputSchema.parse(rawInput); - if (await shouldInitCurrentProject(input)) { + if (options.allowSmartInit && (await shouldInitCurrentProject(input))) { await runInitCommand(input); return; }Then only the root/no-subcommand handler should pass
allowSmartInit: true.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: cf135701-182f-46f6-b585-329832514498
📒 Files selected for processing (5)
README.mdsrc/commands/create.tssrc/commands/init.tssrc/templates/render-init-template.tssrc/types.ts
3f248a2 to
00ab047
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/tasks/setup-prisma.ts (1)
419-475:⚠️ Potential issue | 🟠 MajorValidate required Prisma files against
prismaProjectDir, notprojectDir.Line 464 checks the required-file groups under
projectDir, but Lines 465-475 resolve the singleton underprismaProjectDir. In a monorepo those bases can differ, which means this can reject a validpackages/db/src/client.tswhen the command runs insidepackages/db, or accept an unrelated root-levelsrc/lib/prisma.tsand then return a missingpackages/db/src/client.ts. The validator and resolver need to use the same base directory and the same candidate set.Suggested direction
-const requiredPrismaFileGroups = [ - ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"], - ["prisma/seed.ts", "packages/db/prisma/seed.ts"], - ["prisma.config.ts", "packages/db/prisma.config.ts"], +const requiredPrismaFileGroups = [ + ["prisma/schema.prisma"], + ["prisma/seed.ts"], + ["prisma.config.ts"], [ "src/lib/prisma.ts", "src/lib/prisma.server.ts", "src/lib/server/prisma.ts", "server/utils/prisma.ts", - "packages/db/src/client.ts", + "src/client.ts", ], ] as const; -async function ensureRequiredPrismaFiles( - projectDir: string, +async function ensureRequiredPrismaFiles( + prismaProjectDir: string, singletonPath?: string ): Promise<void> { ... - const absolutePath = path.join(projectDir, relativePath); + const absolutePath = path.join(prismaProjectDir, relativePath); ... } - await ensureRequiredPrismaFiles(projectDir, options.singletonPath); + const normalizedSingletonPath = options.singletonPath + ? path.relative(prismaProjectDir, path.join(projectDir, options.singletonPath)) + : undefined; + await ensureRequiredPrismaFiles(prismaProjectDir, normalizedSingletonPath);
♻️ Duplicate comments (1)
src/commands/init.ts (1)
67-78:⚠️ Potential issue | 🟠 MajorTreat create-only flags as opt-outs from auto-init.
shouldInitCurrentProject()still returnstruefor--force,--skills,--mcp, and--extension. In an existing repo,create-prisma --skillsnow falls intorunInitCommand(), and those flags are silently dropped when the input is re-parsed asPrismaSetupCommandInput.Suggested fix
export async function shouldInitCurrentProject( input: { name?: string; template?: string; + force?: boolean; + skills?: boolean; + mcp?: boolean; + extension?: boolean; }, projectDir = process.cwd() ): Promise<boolean> { - if (input.name || input.template) { + if ( + input.name || + input.template || + input.force || + input.skills || + input.mcp || + input.extension + ) { return false; }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: fa40e948-d606-4956-bf19-856d26313f1a
📒 Files selected for processing (10)
README.mdsrc/commands/create.tssrc/commands/init.tssrc/tasks/setup-prisma.tssrc/templates/render-init-template.tssrc/types.tstemplates/init/prisma-instance.ts.hbstemplates/init/prisma.config.tstemplates/init/prisma/schema.prisma.hbstemplates/init/prisma/seed.ts.hbs
# Conflicts: # README.md # src/tasks/setup-prisma.ts
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/tasks/setup-prisma.ts (1)
57-68:⚠️ Potential issue | 🟠 MajorAccept
src/client.tswhen the current project is alreadypackages/db.The singleton candidate list only includes
packages/db/src/client.ts, butfinalizePrismaFiles()already falls back tosrc/client.tsonceresolvePrismaProjectDir()returns the db package itself. Running init fromrepo/packages/dbwill therefore fail the required-file check even though the singleton exists.💡 Proposed fix
const requiredPrismaFileGroups = [ ["prisma/schema.prisma", "packages/db/prisma/schema.prisma"], ["prisma/seed.ts", "packages/db/prisma/seed.ts"], ["prisma.config.ts", "packages/db/prisma.config.ts"], [ "src/lib/prisma.ts", "src/lib/prisma.server.ts", "src/lib/server/prisma.ts", "server/utils/prisma.ts", + "src/client.ts", "packages/db/src/client.ts", ], ] as const;src/index.ts (1)
16-31:⚠️ Potential issue | 🔴 CriticalRegister the
initsubcommand in the CLI router.The router still only exposes
create, socreate-prisma initis not reachable from the built CLI even thoughrunInitCommand()exists and this PR documentsinitas a public flow.🚨 Suggested fix
import { runCreateCommand } from "./commands/create"; +import { runInitCommand } from "./commands/init"; import { CreateCommandInputSchema, + PrismaSetupCommandInputSchema, type CreateCommandInput, } from "./types"; export const router = os.router({ create: os @@ .handler(async ({ input }) => { await runCreateCommand(input ?? {}, { // Preserve smart init for `create-prisma`, but keep explicit // `create-prisma create` on the scaffolding path. allowInitCurrentProject: !usesExplicitCreateSubcommand(), }); }), + init: os + .meta({ + description: "Initialize Prisma in the current project", + negateBooleans: true, + }) + .input(PrismaSetupCommandInputSchema.optional()) + .handler(async ({ input }) => { + await runInitCommand(input ?? {}); + }), });
♻️ Duplicate comments (3)
README.md (2)
41-50:⚠️ Potential issue | 🟡 MinorAdd the explicit
initusage example.This section still only demonstrates the implicit smart path via bare
create-prisma. Please add acreate-prisma initexample here so users can intentionally choose in-place initialization.
139-144:⚠️ Potential issue | 🟡 MinorDocument Nuxt's singleton file path too.
The generated file list still omits
server/utils/prisma.ts, which is one of the supported singleton locations insrc/tasks/setup-prisma.ts. As written, the README under-documents the Nuxt layout.src/commands/init.ts (1)
67-75:⚠️ Potential issue | 🟠 MajorKeep create-only flags on the scaffolding path.
shouldInitCurrentProject()still only checksnameandtemplate, so commands likecreate-prisma --force,--skills,--mcp, or--extensioninside an existing repo will still flip into init and silently ignore those create-only options.💡 Suggested fix
export async function shouldInitCurrentProject( input: { name?: string; template?: string; + force?: boolean; + skills?: boolean; + mcp?: boolean; + extension?: boolean; }, projectDir = process.cwd() ): Promise<boolean> { - if (input.name || input.template) { + if ( + input.name || + input.template || + input.force || + input.skills || + input.mcp || + input.extension + ) { return false; }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 28b4dad1-2d5c-406e-8e77-a502354ee54a
📒 Files selected for processing (7)
README.mdsrc/commands/create.tssrc/commands/init.tssrc/constants/dependencies.tssrc/index.tssrc/tasks/install.tssrc/tasks/setup-prisma.ts
There was a problem hiding this comment.
♻️ Duplicate comments (2)
README.md (2)
41-45:⚠️ Potential issue | 🟡 MinorDocument the explicit
initcommand.The PR introduces an explicit
create-prisma initcommand, but this section only documents the implicit smart path. Users who want to intentionally initialize Prisma should be able to discover and use the explicit command.📝 Suggested addition
Initialize Prisma in the current project: ```bash create-prisma +# or explicitly: +create-prisma init</details> --- `35-45`: _⚠️ Potential issue_ | _🟡 Minor_ **Clarify the context-dependent behavior in the examples.** Lines 35-39 and 41-45 show identical commands (`create-prisma`) but claim to produce different outcomes. Without additional context markers (such as "when `package.json` exists" vs. "in an empty directory"), readers cannot understand why the same command yields different behaviors. Consider adding inline comments or annotations to each code block that explicitly state the preconditions. <details> <summary>📝 Suggested clarification</summary> ```diff Create a new project in an empty directory: ```bash +# Run this in an empty directory (no package.json) create-prismaInitialize Prisma in the current project:
+# Run this in a directory with package.json create-prisma</details> </blockquote></details> </blockquote></details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Organization UI **Review profile**: ASSERTIVE **Plan**: Pro **Run ID**: `10341b88-ce8f-4b1f-adf7-b795a1d9c2f2` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between fb0c0c3351862d15a9eb246ab1fa042c5f0641a1 and ef41fffdd1db2c09b53c5156ece18047ad2f2393. </details> <details> <summary>📒 Files selected for processing (1)</summary> * `README.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
# Conflicts: # README.md # src/commands/create.ts # src/tasks/setup-prisma.ts # src/utils/package-manager.ts
PR preview published
|
Summary
initwhenpackage.jsonexists and--name/--templateare not providedcreateas the explicit new-project scaffold flowSummary by CodeRabbit
Release Notes
New Features
create-prisma createcommand for non-interactive project creation.Documentation