import type { FileDiffContentsLoader } from "@pierre/diffs";import { squashAtomCommandFailure, type AtomCommandResult,} from "@t3tools/client-runtime/state/runtime";import type { EnvironmentId, PullRequestDiffFileContentsInput, PullRequestDiffFileContentsResult, PullRequestRef, ReviewDiffFileContentsInput, ReviewDiffFileContentsResult, ReviewDiffPreviewSourceKind,} from "@t3tools/contracts"; import { resolveFileDiffPath } from "./diffRendering"; interface GitDiffFileContentsSource { readonly environmentId: EnvironmentId; readonly cwd: string; readonly sourceKind: ReviewDiffPreviewSourceKind; readonly baseRef: string | null; readonly headRef: string | null; /** The comparison identity Pierre carries into its hydrated render cache. */ readonly cacheKey: string;} interface PullRequestDiffFileContentsSource { readonly environmentId: EnvironmentId; readonly reference: PullRequestRef; readonly commit: string | null; readonly cacheKey: string;} type GetDiffFileContents<E> = (request: { readonly environmentId: EnvironmentId; readonly input: ReviewDiffFileContentsInput;}) => Promise<AtomCommandResult<ReviewDiffFileContentsResult, E>>; type GetPullRequestDiffFileContents<E> = (request: { readonly environmentId: EnvironmentId; readonly input: PullRequestDiffFileContentsInput;}) => Promise<AtomCommandResult<PullRequestDiffFileContentsResult, E>>; function createDiffFileContentsLoader( load: (input: { readonly changeType: PullRequestDiffFileContentsInput["changeType"]; readonly oldPath: string; readonly newPath: string; }) => Promise<{ readonly oldContents: string; readonly newContents: string }>, cacheKey: string,): FileDiffContentsLoader { return async (fileDiff) => { const newPath = resolveFileDiffPath(fileDiff); const oldPath = fileDiff.prevName ? resolveFileDiffPath({ ...fileDiff, name: fileDiff.prevName }) : newPath; const contents = await load({ changeType: fileDiff.type, oldPath, newPath }); const newFile = { name: newPath, contents: contents.newContents, cacheKey: `${cacheKey}:new:${newPath}`, }; if (fileDiff.type === "rename-pure") { return { oldFile: null, newFile }; } return { oldFile: { name: oldPath, contents: contents.oldContents, cacheKey: `${cacheKey}:old:${oldPath}`, }, newFile, }; };} /** Turns the host's Git file-content RPC into the full-file loader Pierre uses for hunk expansion. */export function createGitDiffFileContentsLoader<E>( getDiffFileContents: GetDiffFileContents<E>, source: GitDiffFileContentsSource,): FileDiffContentsLoader { return createDiffFileContentsLoader(async ({ changeType, oldPath, newPath }) => { const result = await getDiffFileContents({ environmentId: source.environmentId, input: { cwd: source.cwd, sourceKind: source.sourceKind, changeType, baseRef: source.baseRef, headRef: source.headRef, oldPath, newPath, }, }); if (result._tag !== "Success") { throw squashAtomCommandFailure(result); } return result.value; }, source.cacheKey);} /** Loads host-backed PR files, which may name revisions this checkout has never fetched. */export function createPullRequestDiffFileContentsLoader<E>( getDiffFileContents: GetPullRequestDiffFileContents<E>, source: PullRequestDiffFileContentsSource,): FileDiffContentsLoader { return createDiffFileContentsLoader(async ({ changeType, oldPath, newPath }) => { const result = await getDiffFileContents({ environmentId: source.environmentId, input: { ...source.reference, ...(source.commit === null ? {} : { commit: source.commit }), changeType, oldPath, newPath, }, }); if (result._tag !== "Success") { throw squashAtomCommandFailure(result); } return result.value; }, source.cacheKey);}
import type { FileDiffContentsLoader } from "@pierre/diffs";
import {
squashAtomCommandFailure,
type AtomCommandResult,
} from "@t3tools/client-runtime/state/runtime";
import type {
EnvironmentId,
PullRequestDiffFileContentsInput,
PullRequestDiffFileContentsResult,
PullRequestRef,
ReviewDiffFileContentsInput,
ReviewDiffFileContentsResult,
ReviewDiffPreviewSourceKind,
} from "@t3tools/contracts";
import { resolveFileDiffPath } from "./diffRendering";
interface GitDiffFileContentsSource {
readonly environmentId: EnvironmentId;
readonly cwd: string;
readonly sourceKind: ReviewDiffPreviewSourceKind;
readonly baseRef: string | null;
readonly headRef: string | null;
/** The comparison identity Pierre carries into its hydrated render cache. */
readonly cacheKey: string;
}
interface PullRequestDiffFileContentsSource {
readonly environmentId: EnvironmentId;
readonly reference: PullRequestRef;
readonly commit: string | null;
readonly cacheKey: string;
}
type GetDiffFileContents<E> = (request: {
readonly environmentId: EnvironmentId;
readonly input: ReviewDiffFileContentsInput;
}) => Promise<AtomCommandResult<ReviewDiffFileContentsResult, E>>;
type GetPullRequestDiffFileContents<E> = (request: {
readonly environmentId: EnvironmentId;
readonly input: PullRequestDiffFileContentsInput;
}) => Promise<AtomCommandResult<PullRequestDiffFileContentsResult, E>>;
function createDiffFileContentsLoader(
load: (input: {
readonly changeType: PullRequestDiffFileContentsInput["changeType"];
readonly oldPath: string;
readonly newPath: string;
}) => Promise<{ readonly oldContents: string; readonly newContents: string }>,
cacheKey: string,
): FileDiffContentsLoader {
return async (fileDiff) => {
const newPath = resolveFileDiffPath(fileDiff);
const oldPath = fileDiff.prevName
? resolveFileDiffPath({ ...fileDiff, name: fileDiff.prevName })
: newPath;
const contents = await load({ changeType: fileDiff.type, oldPath, newPath });
const newFile = {
name: newPath,
contents: contents.newContents,
cacheKey: `${cacheKey}:new:${newPath}`,
};
if (fileDiff.type === "rename-pure") {
return { oldFile: null, newFile };
}
return {
oldFile: {
name: oldPath,
contents: contents.oldContents,
cacheKey: `${cacheKey}:old:${oldPath}`,
},
newFile,
};
};
}
/** Turns the host's Git file-content RPC into the full-file loader Pierre uses for hunk expansion. */
export function createGitDiffFileContentsLoader<E>(
getDiffFileContents: GetDiffFileContents<E>,
source: GitDiffFileContentsSource,
): FileDiffContentsLoader {
return createDiffFileContentsLoader(async ({ changeType, oldPath, newPath }) => {
const result = await getDiffFileContents({
environmentId: source.environmentId,
input: {
cwd: source.cwd,
sourceKind: source.sourceKind,
changeType,
baseRef: source.baseRef,
headRef: source.headRef,
oldPath,
newPath,
},
});
if (result._tag !== "Success") {
throw squashAtomCommandFailure(result);
}
return result.value;
}, source.cacheKey);
}
/** Loads host-backed PR files, which may name revisions this checkout has never fetched. */
export function createPullRequestDiffFileContentsLoader<E>(
getDiffFileContents: GetPullRequestDiffFileContents<E>,
source: PullRequestDiffFileContentsSource,
): FileDiffContentsLoader {
return createDiffFileContentsLoader(async ({ changeType, oldPath, newPath }) => {
const result = await getDiffFileContents({
environmentId: source.environmentId,
input: {
...source.reference,
...(source.commit === null ? {} : { commit: source.commit }),
changeType,
oldPath,
newPath,
},
});
if (result._tag !== "Success") {
throw squashAtomCommandFailure(result);
}
return result.value;
}, source.cacheKey);
}