feat(generators): wire trpc entry + e2e test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-09 14:08:26 +02:00
parent 36bae3513d
commit d216250ccd
2 changed files with 93 additions and 1 deletions

View File

@@ -0,0 +1,51 @@
import { describe, it, expect } from "vitest";
import { mkdtempSync, cpSync, readFileSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { execSync } from "node:child_process";
import { join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { computeSnapshot } from "../lib/snapshot";
import expectedSnapshot from "../__snapshots__/core-package/trpc.snapshot.json";
// Repo root is 2 levels up from turbo/generators/__tests__
const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", "..");
/**
* Strip "@repo/core-trpc" from a package.json file in the tmp tree.
* Required when simulating a fresh scaffold: core-trpc does not exist yet
* but the snapshot was captured before removal. Apps in the current tree
* still list it as a dependency.
*/
function stripCoreTrpcDep(pkgJsonPath: string): void {
const raw = readFileSync(pkgJsonPath, "utf8");
const parsed = JSON.parse(raw) as Record<string, Record<string, string>>;
for (const section of ["dependencies", "devDependencies", "peerDependencies"] as const) {
if (parsed[section]?.["@repo/core-trpc"]) {
delete parsed[section]["@repo/core-trpc"];
}
}
writeFileSync(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n");
}
describe("e2e: core-package trpc", () => {
it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => {
const tmp = mkdtempSync(join(tmpdir(), "e2e-trpc-"));
cpSync(REPO_ROOT, tmp, {
recursive: true,
filter: (src) =>
!src.includes("node_modules") &&
!src.includes(".turbo") &&
!src.includes("packages/core-trpc"),
});
// Strip @repo/core-trpc from app package.json files so pnpm install
// succeeds without the package being present (simulating the post-removal state).
stripCoreTrpcDep(join(tmp, "apps", "web-next", "package.json"));
stripCoreTrpcDep(join(tmp, "apps", "web-tanstack", "package.json"));
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" });
execSync(`cd ${tmp} && pnpm turbo gen core-package --args trpc`, { stdio: "ignore" });
const result = computeSnapshot(join(tmp, "packages/core-trpc"));
expect(result).toEqual(expectedSnapshot);
});
});

View File

@@ -642,6 +642,18 @@ import noRealtimeHandlerReexport from "./rules/no-realtime-handler-reexport.js";
},
printEventsNextSteps,
],
trpc: () => [
() => {
assertOptionalPackageNotPresent("core-trpc");
return "Guard passed — packages/core-trpc does not exist yet.";
},
...emitTemplateTree("core-package/trpc", "packages/core-trpc"),
() => {
addToTranspilePackages("apps/web-next/next.config.mjs", "@repo/core-trpc");
return "Added @repo/core-trpc to transpilePackages.";
},
printTrpcNextSteps,
],
};
plop.setGenerator("core-package", {
@@ -651,7 +663,7 @@ import noRealtimeHandlerReexport from "./rules/no-realtime-handler-reexport.js";
type: "list",
name: "name",
message: "Which optional core package?",
choices: ["realtime", "events"],
choices: ["realtime", "events", "trpc"],
},
],
actions: (answers) => {
@@ -1146,6 +1158,35 @@ function printHandlerNextSteps(a: {
].join("\n");
}
function printTrpcNextSteps(): string {
return [
"─────────────────────────────────────────────────────────────",
"@repo/core-trpc scaffolded.",
"",
"Next steps (manual wiring — not generated):",
"",
" 1. pnpm install # link the new workspace package",
"",
" 2. apps/web-next/src/app/providers.tsx:",
' - import { NextTrpcProvider } from "@repo/core-trpc/next";',
" - wrap children: <NextTrpcProvider trpcUrl=\"/api/trpc\">{children}</NextTrpcProvider>",
"",
" 3. apps/web-next/src/app/api/trpc/[trpc]/route.ts:",
' - import { fetchRequestHandler } from "@trpc/server/adapters/fetch";',
' - import { appRouter } from "@repo/core-api";',
" - export GET and POST handlers using fetchRequestHandler",
"",
" 4. apps/web-tanstack/src/routes/__root.tsx:",
' - import { TanstackTrpcProvider } from "@repo/core-trpc/tanstack";',
" - wrap <Outlet /> with <TanstackTrpcProvider trpcUrl=\"http://localhost:3000/api/trpc\">",
"",
" 5. Add @repo/core-trpc to apps/web-next/package.json and apps/web-tanstack/package.json dependencies",
"",
" 6. pnpm typecheck && pnpm lint && pnpm test",
"─────────────────────────────────────────────────────────────",
].join("\n");
}
function printEventsNextSteps(): string {
return [
"─────────────────────────────────────────────────────────────",