diff --git a/scripts/lib/format-generated-module.d.mts b/scripts/lib/format-generated-module.d.mts index f4e1579af4b9..eb1bf34ebfe4 100644 --- a/scripts/lib/format-generated-module.d.mts +++ b/scripts/lib/format-generated-module.d.mts @@ -1,37 +1,7 @@ -/** Resolve the fastest available oxfmt command for a generated module path. */ -export function resolveGeneratedModuleFormatter(params: { - existsSync: (value: string) => boolean; - comSpec?: string; - env?: NodeJS.ProcessEnv; - npmExecPath?: string; - outputPath: string; - platform: NodeJS.Platform; - repoRoot: string; -}): - | { - args: string[]; - command: string; - env?: NodeJS.ProcessEnv; - shell: boolean; - windowsVerbatimArguments?: boolean; - } - | { - command: string; - args: unknown[]; - shell: boolean; - }; /** Format generated source in a temporary file and return the formatter output. */ export function formatGeneratedModule( - source: unknown, - { - repoRoot, - outputPath, - errorLabel, - }: { - repoRoot: unknown; - outputPath: unknown; - errorLabel: unknown; - }, + source: string, + options: { repoRoot: string; outputPath: string; errorLabel: string }, deps?: Record, ): string; export const GENERATED_MODULE_FORMAT_TIMEOUT_MS: 30000; diff --git a/scripts/lib/format-generated-module.mjs b/scripts/lib/format-generated-module.mjs index 7775b0d12460..447f87d9af8b 100644 --- a/scripts/lib/format-generated-module.mjs +++ b/scripts/lib/format-generated-module.mjs @@ -3,37 +3,11 @@ import { spawnSync } from "node:child_process"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { resolvePnpmRunner } from "../pnpm-runner.mjs"; export const GENERATED_MODULE_FORMAT_TIMEOUT_MS = 30_000; export const GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES = 1024 * 1024; const FORMATTER_OUTPUT_TAIL_BYTES = 16 * 1024; -/** Resolve the fastest available oxfmt command for a generated module path. */ -export function resolveGeneratedModuleFormatter(params) { - const platform = params.platform ?? process.platform; - const existsSync = params.existsSync ?? fs.existsSync; - const directFormatterPath = path.join(params.repoRoot, "node_modules", ".bin", "oxfmt"); - const useDirectFormatter = platform !== "win32" && existsSync(directFormatterPath); - if (useDirectFormatter) { - return { - command: directFormatterPath, - args: ["--write", params.outputPath], - shell: false, - }; - } - - return resolvePnpmRunner({ - comSpec: params.comSpec, - cwd: params.repoRoot, - env: params.env, - npmExecPath: params.npmExecPath, - nodeExecPath: params.nodeExecPath, - platform, - pnpmArgs: ["exec", "oxfmt", "--write", params.outputPath], - }); -} - function outputText(value) { if (typeof value === "string") { return value; @@ -86,31 +60,27 @@ function formatterFailureDetails(formatter) { /** Format generated source in a temporary file and return the formatter output. */ export function formatGeneratedModule(source, { repoRoot, outputPath, errorLabel }, deps = {}) { const spawnSyncImpl = deps.spawnSync ?? spawnSync; - const resolveFormatter = deps.resolveFormatter ?? resolveGeneratedModuleFormatter; const resolvedRepoRoot = path.resolve(repoRoot); - const resolvedOutputPath = path.resolve( - resolvedRepoRoot, - path.isAbsolute(outputPath) ? path.relative(resolvedRepoRoot, outputPath) : outputPath, - ); const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-generated-format-")); - const tempOutputPath = path.join(tempDir, path.basename(resolvedOutputPath)); + const tempOutputPath = path.join(tempDir, path.basename(outputPath)); try { fs.writeFileSync(tempOutputPath, source, "utf8"); - const command = resolveFormatter({ - existsSync: fs.existsSync, - outputPath: tempOutputPath, - repoRoot: resolvedRepoRoot, - }); - const formatter = spawnSyncImpl(command.command, command.args, { - cwd: resolvedRepoRoot, - encoding: "utf8", - env: command.env ?? process.env, - maxBuffer: GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES, - shell: command.shell, - timeout: GENERATED_MODULE_FORMAT_TIMEOUT_MS, - windowsVerbatimArguments: command.windowsVerbatimArguments, - }); + const formatter = spawnSyncImpl( + process.execPath, + [ + path.join(resolvedRepoRoot, "node_modules", "oxfmt", "bin", "oxfmt"), + "--write", + tempOutputPath, + ], + { + cwd: resolvedRepoRoot, + encoding: "utf8", + maxBuffer: GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES, + shell: false, + timeout: GENERATED_MODULE_FORMAT_TIMEOUT_MS, + }, + ); if (formatter.error || formatter.status !== 0) { const details = formatterFailureDetails(formatter); throw new Error(`failed to format generated ${errorLabel}: ${details}`); diff --git a/test/scripts/format-generated-module.test.ts b/test/scripts/format-generated-module.test.ts index 725a60de4e1d..6de8533a081b 100644 --- a/test/scripts/format-generated-module.test.ts +++ b/test/scripts/format-generated-module.test.ts @@ -1,5 +1,5 @@ // Format Generated Module tests cover format generated module script behavior. -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; @@ -7,7 +7,6 @@ import { formatGeneratedModule, GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES, GENERATED_MODULE_FORMAT_TIMEOUT_MS, - resolveGeneratedModuleFormatter, } from "../../scripts/lib/format-generated-module.mjs"; const tempDirs: string[] = []; @@ -15,9 +14,6 @@ const tempDirs: string[] = []; function makeRepoRoot() { const repoRoot = mkdtempSync(path.join(os.tmpdir(), "openclaw-format-generated-module-")); tempDirs.push(repoRoot); - const formatterDir = path.join(repoRoot, "node_modules", ".bin"); - mkdirSync(formatterDir, { recursive: true }); - writeFileSync(path.join(formatterDir, "oxfmt"), "#!/bin/sh\n", "utf8"); return repoRoot; } @@ -27,48 +23,7 @@ afterEach(() => { } }); -describe("resolveGeneratedModuleFormatter", () => { - it("uses the direct formatter binary on non-Windows when available", () => { - const formatterPath = path.join("/repo", "node_modules", ".bin", "oxfmt"); - - expect( - resolveGeneratedModuleFormatter({ - existsSync: (value) => value === formatterPath, - outputPath: "/tmp/generated.ts", - platform: "linux", - repoRoot: "/repo", - }), - ).toEqual({ - command: formatterPath, - args: ["--write", "/tmp/generated.ts"], - shell: false, - }); - }); - - it("wraps pnpm.cmd explicitly on Windows instead of using shell mode", () => { - expect( - resolveGeneratedModuleFormatter({ - comSpec: "C:\\Windows\\System32\\cmd.exe", - env: { PATH: "" }, - existsSync: () => false, - npmExecPath: "", - outputPath: "C:\\Users\\test\\AppData\\Local\\Temp\\generated output.ts", - platform: "win32", - repoRoot: "C:\\repo", - }), - ).toEqual({ - command: "C:\\Windows\\System32\\cmd.exe", - args: [ - "/d", - "/s", - "/c", - 'pnpm.cmd exec oxfmt --write "C:\\Users\\test\\AppData\\Local\\Temp\\generated output.ts"', - ], - shell: false, - windowsVerbatimArguments: true, - }); - }); - +describe("formatGeneratedModule", () => { it("runs generated module formatting with bounded child execution", () => { const repoRoot = makeRepoRoot(); const calls: unknown[] = []; @@ -81,14 +36,9 @@ describe("resolveGeneratedModuleFormatter", () => { repoRoot, }, { - resolveFormatter: ({ outputPath }: { outputPath: string }) => ({ - args: ["--write", outputPath], - command: "oxfmt", - shell: false, - }), - spawnSync: (_command: string, args: string[], options: unknown) => { - calls.push(options); - writeFileSync(args[1] ?? "", "export const value = 1;\n", "utf8"); + spawnSync: (command: string, args: string[], options: unknown) => { + calls.push({ args, command, options }); + writeFileSync(args[2] ?? "", "export const value = 1;\n", "utf8"); return { status: 0, stderr: "", stdout: "" }; }, }, @@ -97,11 +47,19 @@ describe("resolveGeneratedModuleFormatter", () => { expect(formatted).toBe("export const value = 1;\n"); expect(calls).toHaveLength(1); expect(calls[0]).toMatchObject({ - cwd: repoRoot, - encoding: "utf8", - maxBuffer: GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES, - shell: false, - timeout: GENERATED_MODULE_FORMAT_TIMEOUT_MS, + args: [ + path.join(repoRoot, "node_modules", "oxfmt", "bin", "oxfmt"), + "--write", + expect.stringMatching(/generated\.ts$/u), + ], + command: process.execPath, + options: { + cwd: repoRoot, + encoding: "utf8", + maxBuffer: GENERATED_MODULE_FORMAT_MAX_BUFFER_BYTES, + shell: false, + timeout: GENERATED_MODULE_FORMAT_TIMEOUT_MS, + }, }); }); @@ -120,11 +78,6 @@ describe("resolveGeneratedModuleFormatter", () => { repoRoot, }, { - resolveFormatter: ({ outputPath }: { outputPath: string }) => ({ - args: ["--write", outputPath], - command: "oxfmt", - shell: false, - }), spawnSync: () => ({ error: timeoutError, signal: "SIGTERM", @@ -147,11 +100,6 @@ describe("resolveGeneratedModuleFormatter", () => { repoRoot, }, { - resolveFormatter: ({ outputPath }: { outputPath: string }) => ({ - args: ["--write", outputPath], - command: "oxfmt", - shell: false, - }), spawnSync: () => ({ error: timeoutError, signal: "SIGTERM",