UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines • 13.9 kB
{"version":3,"file":"migrate-pnpm.mjs","names":[],"sources":["../../../../../src/services/scaffold/upgrade-audit/steps/migrate-pnpm.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { listFiles, readText, removePath, writeText } from \"../fs\";\nimport type { StepResult } from \"./author-config\";\n\nconst V2_CATALOG: Readonly<Record<string, string>> = {\n \"everything-dev\": \"^2.0.0-rc.14\",\n \"every-plugin\": \"^3.0.0-rc.9\",\n \"better-near-auth\": \"^2.0.0-rc.2\",\n effect: \"4.0.0-rc.117\",\n zod: \"4.6.5\",\n \"better-auth\": \"1.7.7\",\n \"@better-auth/api-key\": \"1.7.7\",\n \"@better-auth/passkey\": \"1.7.7\",\n \"@better-auth/core\": \"1.7.7\",\n \"@orpc/contract\": \"2.0.0-beta.35\",\n \"@orpc/server\": \"2.0.0-beta.35\",\n \"@orpc/client\": \"2.0.0-beta.35\",\n \"@orpc/zod\": \"2.0.0-beta.35\",\n \"@orpc/openapi\": \"2.0.0-beta.35\",\n \"@orpc/tanstack-query\": \"2.0.0-beta.35\",\n \"@orpc/publisher\": \"2.0.0-beta.35\",\n \"@orpc/experimental-effect\": \"2.0.0-beta.35\",\n \"@tanstack/react-query\": \"5.104.5\",\n \"@tanstack/react-query-devtools\": \"^5.104.5\",\n \"@tanstack/react-router\": \"1.170.45\",\n \"@tanstack/react-router-devtools\": \"1.167.2\",\n \"@tanstack/router-generator\": \"1.167.45\",\n \"@tanstack/router-plugin\": \"1.168.47\",\n \"@tanstack/react-devtools\": \"^0.10.13\",\n \"@tanstack/react-table\": \"^9.3.1\",\n \"near-kit\": \"^0.20.2\",\n \"@module-federation/enhanced\": \"^2.9.2\",\n \"@module-federation/node\": \"^2.7.52\",\n \"@module-federation/rsbuild-plugin\": \"^2.9.2\",\n \"@module-federation/runtime-core\": \"^2.9.2\",\n \"@module-federation/runtime\": \"^2.9.2\",\n \"@module-federation/runtime-tools\": \"^2.9.2\",\n \"@module-federation/sdk\": \"^2.9.2\",\n \"@module-federation/dts-plugin\": \"^2.9.2\",\n \"@rspack/core\": \"2.2.9\",\n \"@rspack/cli\": \"2.2.9\",\n \"@rsbuild/core\": \"2.2.14\",\n \"@rsbuild/plugin-react\": \"2.1.1\",\n typescript: \"^7.0.2\",\n};\n\nconst MINIMUM_RELEASE_AGE_EXCLUDE = [\n \"better-near-auth@2.0.0-rc.0 || 2.0.0-rc.1 || 2.0.0-rc.2\",\n \"every-plugin@3.0.0-rc.4 || 3.0.0-rc.5 || 3.0.0-rc.6 || 3.0.0-rc.7 || 3.0.0-rc.8 || 3.0.0-rc.9\",\n \"everything-dev@2.0.0-rc.7 || 2.0.0-rc.8 || 2.0.0-rc.9 || 2.0.0-rc.10 || 2.0.0-rc.11 || 2.0.0-rc.12 || 2.0.0-rc.13 || 2.0.0-rc.14\",\n];\n\nconst PNPM_PACKAGE_MANAGER = \"pnpm@12.10.1\";\n\n/**\n * Transitive dedupe pins. @tanstack/react-router-devtools drags in a\n * different @tanstack/router-core than @tanstack/react-router resolves, so\n * everything-dev's dist (which imports the hoisted core) disagrees with the\n * app-typed RouterCore — every AppRouterFactory assignment fails with\n * missing `routeBranchCache`/`resolvePathWithBase`/`getRouteBranch`, and the\n * stale react-router variant breaks `bos types gen` at import time\n * (`isPlainArray` no longer exported). Force one core/router pair\n * everywhere; bump in lockstep with the react-router catalog pin.\n */\nconst TRANSITIVE_OVERRIDES: Readonly<Record<string, string>> = {\n \"@tanstack/router-core\": \"1.171.38\",\n \"@tanstack/react-router\": \"1.170.45\",\n};\n\nconst YAML_PLAIN_VALUE_RE = /^[A-Za-z0-9^~][A-Za-z0-9.^~*+\\-/]*$/;\n\nconst yamlScalar = (value: string): string =>\n YAML_PLAIN_VALUE_RE.test(value) ? value : JSON.stringify(value);\n\nconst yamlMap = (entries: ReadonlyArray<readonly [string, string]>, indent: string): string =>\n entries\n .map(([key, value]) =>\n /^[A-Za-z0-9_.-]+$/.test(key)\n ? `${indent}${key}: ${yamlScalar(value)}`\n : `${indent}${JSON.stringify(key)}: ${yamlScalar(value)}`,\n )\n .join(\"\\n\");\n\ninterface WorkspaceYamlInput {\n readonly packages: readonly string[];\n readonly catalog: Readonly<Record<string, string>>;\n}\n\nconst renderWorkspaceYaml = (input: WorkspaceYamlInput): string => {\n const catalogEntries = Object.entries(input.catalog).map(([key, value]) => [key, value] as const);\n const lines = [\n \"packages:\",\n ...input.packages.map((pkg) => ` - ${yamlScalar(pkg)}`),\n \"\",\n \"allowBuilds:\",\n \" esbuild: true\",\n \" sharp: true\",\n \" protobufjs: true\",\n \" '@openapitools/openapi-generator-cli': true\",\n \"\",\n \"overrides:\",\n ...Object.entries(TRANSITIVE_OVERRIDES).map(\n ([key, value]) => ` ${yamlMap([[key, value]], \"\").trimStart()}`,\n ),\n \"\",\n \"catalog:\",\n yamlMap(catalogEntries, \" \"),\n \"\",\n \"minimumReleaseAgeExclude:\",\n ...MINIMUM_RELEASE_AGE_EXCLUDE.map((entry) => ` - ${yamlScalar(entry)}`),\n \"\",\n ];\n return lines.join(\"\\n\");\n};\n\nconst PLUGIN_TYPECHECK_LOOP =\n 'for dir in plugins/*; do if [ -f \"$dir/package.json\" ]; then pnpm --dir \"$dir\" run typecheck || exit 1; fi; done';\n\nconst PLUGIN_TEST_LOOP =\n 'for d in plugins/*; do if [ -f \"$d/package.json\" ]; then pnpm --dir \"$d\" --if-present run test || exit 1; fi; done';\n\nconst hardenedTypecheck = (dirs: readonly string[]): string =>\n [\n \"pnpm run types:gen\",\n ...dirs.map((dir) => `if [ -d ${dir} ]; then pnpm --dir ${dir} run typecheck || exit 1; fi`),\n PLUGIN_TYPECHECK_LOOP,\n ].join(\" && \");\n\nconst hardenedTest = (dirs: readonly string[]): string =>\n [\n ...dirs.map((dir) => `pnpm --dir ${dir} --if-present run test || exit 1`),\n `[ -d plugins ] && ${PLUGIN_TEST_LOOP} || true`,\n ].join(\" && \");\n\n/** Mechanical bun→pnpm rewrites, safe for any workspace's scripts. */\nconst mechanicalScriptRewrite = (value: string): string =>\n value\n .replaceAll(\"bun run --if-present --cwd \", \"pnpm --dir \")\n .replaceAll(\"bun run --cwd \", \"pnpm --dir \")\n .replace(/bun run --cwd (\\S+) (.+)/, \"pnpm --dir $1 exec $2\")\n .replaceAll(\"bun run \", \"pnpm run \")\n // node cannot execute the .bin shell shims pnpm installs — under pnpm\n // run, the bin is already on PATH.\n .replace(/node node_modules\\/\\.bin\\/bos /, \"bos \")\n .replace(\n 'for d in plugins/*; do [ -f \"$d/package.json\" ] && bun run --if-present --cwd \"$d\" test; done',\n 'for d in plugins/*; do if [ -f \"$d/package.json\" ]; then pnpm --dir \"$d\" --if-present run test || exit 1; fi; done',\n )\n .replace(\n 'for dir in plugins/*; do if [ -f \"$dir/package.json\" ]; then bun run --cwd \"$dir\" typecheck; fi; done',\n 'for dir in plugins/*; do if [ -f \"$dir/package.json\" ]; then pnpm --dir \"$dir\" run typecheck || exit 1; fi; done',\n );\n\nconst rewriteScripts = (scripts: Record<string, string>): Record<string, string> => {\n const next: Record<string, string> = {};\n for (const [key, value] of Object.entries(scripts)) {\n if (key === \"typecheck\") {\n next[key] = hardenedTypecheck([\"ui\", \"api\"]);\n continue;\n }\n if (key === \"test\") {\n next[key] = hardenedTest([\"api\", \"ui\"]);\n continue;\n }\n next[key] = mechanicalScriptRewrite(value);\n }\n return next;\n};\n\nconst WORKSPACE_PKG_GLOB = \"{ui/package.json,api/package.json,plugins/*/package.json}\";\n\n/**\n * Workspace package.json scripts still speak bun (`bun run build:client`,\n * `bun run --cwd api typecheck`). Rewrite every bun invocation to the pnpm\n * form so the pnpm-only tree (packageManager pin, no bun in CI) works.\n * Unlike the root pass, workspace typecheck/test scripts keep their own\n * bodies — only the bun invocations are mechanically rewritten.\n */\nconst rewriteWorkspaceScripts = (\n projectDir: string,\n dryRun: boolean,\n): Effect.Effect<string[], Error> =>\n Effect.gen(function* () {\n const pkgPaths = yield* listFiles(projectDir, WORKSPACE_PKG_GLOB);\n const changed: string[] = [];\n for (const pkgPath of pkgPaths) {\n const source = yield* readText(projectDir, pkgPath);\n if (!source.includes(\"bun \")) continue;\n const pkg = JSON.parse(source) as { scripts?: Record<string, string> };\n if (!pkg.scripts) continue;\n const scripts = Object.fromEntries(\n Object.entries(pkg.scripts).map(([key, value]) => [key, mechanicalScriptRewrite(value)]),\n );\n if (JSON.stringify(scripts) === JSON.stringify(pkg.scripts)) continue;\n if (!dryRun) {\n yield* writeText(projectDir, pkgPath, `${JSON.stringify({ ...pkg, scripts }, null, 2)}\\n`);\n }\n changed.push(pkgPath);\n }\n return changed;\n });\n\nconst BUN_ARTIFACTS = [\"bun.lock\", \"bunfig.toml\"] as const;\n\nconst RETIRED_FILES = [\"railway.toml\", \"Dockerfile\"] as const;\n\nexport const migratePnpm = (\n projectDir: string,\n dryRun: boolean,\n): Effect.Effect<StepResult, Error> =>\n Effect.gen(function* () {\n const pkg = JSON.parse(yield* readText(projectDir, \"package.json\")) as {\n packageManager?: string;\n scripts?: Record<string, string>;\n workspaces?: { packages?: string[]; catalog?: Record<string, string> };\n };\n\n const catalog = { ...(pkg.workspaces?.catalog ?? {}), ...V2_CATALOG };\n const packages = pkg.workspaces?.packages ?? [\"api\", \"ui\", \"plugins/*\"];\n const workspaceYaml = renderWorkspaceYaml({ packages, catalog });\n\n const nextPkg = {\n ...pkg,\n packageManager: PNPM_PACKAGE_MANAGER,\n scripts: rewriteScripts(pkg.scripts ?? {}),\n workspaces: undefined,\n };\n\n const writes = [\"pnpm-workspace.yaml\", \"package.json\"];\n const deletes = [...BUN_ARTIFACTS, ...RETIRED_FILES];\n const notes = [\n \"catalog now lives in pnpm-workspace.yaml; bos upgrade syncs framework versions from the parent\",\n \"Dockerfile + railway.toml retired — deploys use ci.image (the upstream runtime image)\",\n ];\n\n const workspaceScripts = yield* rewriteWorkspaceScripts(projectDir, dryRun);\n\n if (dryRun) {\n return {\n writes: [...writes, ...workspaceScripts],\n deletes,\n notes,\n };\n }\n\n yield* writeText(projectDir, \"pnpm-workspace.yaml\", workspaceYaml);\n yield* writeText(projectDir, \"package.json\", `${JSON.stringify(nextPkg, null, 2)}\\n`);\n for (const path of [...BUN_ARTIFACTS, ...RETIRED_FILES]) {\n yield* removePath(projectDir, path);\n }\n return { writes: [...writes, ...workspaceScripts], deletes, notes };\n });\n"],"mappings":"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"}