mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-13 03:36:11 +00:00
* fix(diffs): share SSR preloads and repair language-pack hydration Render viewer and file documents from a single @pierre/diffs SSR preload per file (mode=both previously ran the full diff+highlight pipeline twice; 651ms -> 303ms on an 8-file patch), apply the file-mode font bump as a document-level override, and keep hydration payloads variant-faithful. Fix the language-pack runtime downgrading pack-only languages to plain text at hydration by defining a per-target build flag and forwarding it to payload normalization. Also: case-insensitive language hints, identical before/after short-circuit with details.changed, patch input failures classified as tool input errors, canonical config values now win over deprecated aliases, hash-pinned viewer runtime served immutable, truthful browser-vs-render errors, timing-safe artifact token compare, unref idle browser timer. * docs(changelog): link diffs rendering entry to PR * test(diffs): narrow manifest validation results before value access * test(tooling): allowlist diffs viewer-client define suppression
246 lines
6.9 KiB
TypeScript
246 lines
6.9 KiB
TypeScript
// Diffs tests cover language hints plugin behavior.
|
|
import type { FileDiffMetadata } from "@pierre/diffs";
|
|
import { describe, expect, it } from "vitest";
|
|
import {
|
|
normalizeDiffViewerPayloadLanguages,
|
|
normalizeSupportedLanguageHint,
|
|
} from "./language-hints.js";
|
|
|
|
async function normalizeHints(values: readonly string[], options = {}) {
|
|
return await Promise.all(values.map((value) => normalizeSupportedLanguageHint(value, options)));
|
|
}
|
|
|
|
describe("normalizeSupportedLanguageHint", () => {
|
|
it("keeps supported languages", async () => {
|
|
await expect(normalizeHints(["typescript", "cpp", "text"])).resolves.toEqual([
|
|
"typescript",
|
|
"cpp",
|
|
"text",
|
|
]);
|
|
});
|
|
|
|
it("normalizes language hint casing", async () => {
|
|
await expect(normalizeHints(["Python", "TypeScript"])).resolves.toEqual([
|
|
"python",
|
|
"typescript",
|
|
]);
|
|
await expect(
|
|
normalizeSupportedLanguageHint("AbAp", { languagePackAvailable: true }),
|
|
).resolves.toBe("abap");
|
|
});
|
|
|
|
it("normalizes common aliases to base viewer languages", async () => {
|
|
await expect(
|
|
normalizeHints(["ts", "c++", "c#", "bash", "dockerfile", "rb", "kt", "ps1"]),
|
|
).resolves.toEqual([
|
|
"typescript",
|
|
"cpp",
|
|
"csharp",
|
|
"sh",
|
|
"docker",
|
|
"ruby",
|
|
"kotlin",
|
|
"powershell",
|
|
]);
|
|
});
|
|
|
|
it("keeps mainstream languages in the base viewer without the language pack", async () => {
|
|
await expect(
|
|
normalizeHints(["ruby", "swift", "kotlin", "r", "dart", "lua", "powershell", "xml", "toml"]),
|
|
).resolves.toEqual([
|
|
"ruby",
|
|
"swift",
|
|
"kotlin",
|
|
"r",
|
|
"dart",
|
|
"lua",
|
|
"powershell",
|
|
"xml",
|
|
"toml",
|
|
]);
|
|
});
|
|
|
|
it("drops uncommon languages without the language pack", async () => {
|
|
await expect(normalizeSupportedLanguageHint("abap")).resolves.toBeUndefined();
|
|
});
|
|
|
|
it("keeps uncommon languages when the language pack is available", async () => {
|
|
await expect(
|
|
normalizeSupportedLanguageHint("abap", { languagePackAvailable: true }),
|
|
).resolves.toBe("abap");
|
|
});
|
|
|
|
it("drops invalid languages", async () => {
|
|
await expect(normalizeSupportedLanguageHint("not-a-real-language")).resolves.toBeUndefined();
|
|
});
|
|
|
|
it("keeps valid languages when invalid hints are mixed in", async () => {
|
|
await expect(normalizeHints(["typescript", "not-a-real-language"])).resolves.toEqual([
|
|
"typescript",
|
|
undefined,
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("normalizeDiffViewerPayloadLanguages", () => {
|
|
it("rewrites stale patch payload language overrides to plain text", async () => {
|
|
const result = await normalizeDiffViewerPayloadLanguages({
|
|
prerenderedHTML: "<div>diff</div>",
|
|
options: {
|
|
theme: {
|
|
light: "pierre-light",
|
|
dark: "pierre-dark",
|
|
},
|
|
diffStyle: "unified",
|
|
diffIndicators: "bars",
|
|
disableLineNumbers: false,
|
|
expandUnchanged: false,
|
|
themeType: "dark",
|
|
backgroundEnabled: true,
|
|
overflow: "wrap",
|
|
unsafeCSS: "",
|
|
},
|
|
langs: ["not-a-real-language" as never],
|
|
fileDiff: {
|
|
name: "foo.txt",
|
|
lang: "not-a-real-language" as never,
|
|
} as unknown as FileDiffMetadata,
|
|
});
|
|
|
|
expect(result.langs).toEqual(["text"]);
|
|
expect(result.fileDiff?.lang).toBe("text");
|
|
});
|
|
|
|
it("keeps valid hydrated languages and only downgrades invalid sides", async () => {
|
|
const result = await normalizeDiffViewerPayloadLanguages({
|
|
prerenderedHTML: "<div>diff</div>",
|
|
options: {
|
|
theme: {
|
|
light: "pierre-light",
|
|
dark: "pierre-dark",
|
|
},
|
|
diffStyle: "split",
|
|
diffIndicators: "classic",
|
|
disableLineNumbers: true,
|
|
expandUnchanged: true,
|
|
themeType: "light",
|
|
backgroundEnabled: false,
|
|
overflow: "scroll",
|
|
unsafeCSS: "",
|
|
},
|
|
langs: ["typescript", "not-a-real-language" as never],
|
|
oldFile: {
|
|
name: "before.unknown",
|
|
contents: "before",
|
|
lang: "not-a-real-language" as never,
|
|
},
|
|
newFile: {
|
|
name: "after.ts",
|
|
contents: "after",
|
|
lang: "typescript",
|
|
},
|
|
});
|
|
|
|
expect(result.langs).toEqual(["typescript", "text"]);
|
|
expect(result.oldFile?.lang).toBe("text");
|
|
expect(result.newFile?.lang).toBe("typescript");
|
|
});
|
|
|
|
it("keeps uncommon hydrated languages when the language pack is available", async () => {
|
|
const result = await normalizeDiffViewerPayloadLanguages(
|
|
{
|
|
prerenderedHTML: "<div>diff</div>",
|
|
options: {
|
|
theme: {
|
|
light: "pierre-light",
|
|
dark: "pierre-dark",
|
|
},
|
|
diffStyle: "unified",
|
|
diffIndicators: "bars",
|
|
disableLineNumbers: false,
|
|
expandUnchanged: false,
|
|
themeType: "dark",
|
|
backgroundEnabled: true,
|
|
overflow: "wrap",
|
|
unsafeCSS: "",
|
|
},
|
|
langs: ["abap" as never],
|
|
fileDiff: {
|
|
name: "demo.abap",
|
|
lang: "abap" as never,
|
|
} as unknown as FileDiffMetadata,
|
|
},
|
|
{ languagePackAvailable: true },
|
|
);
|
|
|
|
expect(result.langs).toEqual(["abap"]);
|
|
expect(result.fileDiff?.lang).toBe("abap");
|
|
});
|
|
|
|
it("rewrites blank explicit language overrides to plain text", async () => {
|
|
const result = await normalizeDiffViewerPayloadLanguages({
|
|
prerenderedHTML: "<div>diff</div>",
|
|
options: {
|
|
theme: {
|
|
light: "pierre-light",
|
|
dark: "pierre-dark",
|
|
},
|
|
diffStyle: "unified",
|
|
diffIndicators: "bars",
|
|
disableLineNumbers: false,
|
|
expandUnchanged: false,
|
|
themeType: "dark",
|
|
backgroundEnabled: true,
|
|
overflow: "wrap",
|
|
unsafeCSS: "",
|
|
},
|
|
langs: [" " as never],
|
|
oldFile: {
|
|
name: "before.unknown",
|
|
contents: "before",
|
|
lang: " " as never,
|
|
},
|
|
newFile: {
|
|
name: "after.txt",
|
|
contents: "after",
|
|
},
|
|
});
|
|
|
|
expect(result.langs).toEqual(["text"]);
|
|
expect(result.oldFile?.lang).toBe("text");
|
|
});
|
|
|
|
it("does not inject text when a valid file language is the only supported hint", async () => {
|
|
const result = await normalizeDiffViewerPayloadLanguages({
|
|
prerenderedHTML: "<div>diff</div>",
|
|
options: {
|
|
theme: {
|
|
light: "pierre-light",
|
|
dark: "pierre-dark",
|
|
},
|
|
diffStyle: "unified",
|
|
diffIndicators: "bars",
|
|
disableLineNumbers: false,
|
|
expandUnchanged: false,
|
|
themeType: "dark",
|
|
backgroundEnabled: true,
|
|
overflow: "wrap",
|
|
unsafeCSS: "",
|
|
},
|
|
langs: [],
|
|
oldFile: {
|
|
name: "before.ts",
|
|
contents: "before",
|
|
lang: "typescript",
|
|
},
|
|
newFile: {
|
|
name: "after.ts",
|
|
contents: "after",
|
|
lang: "typescript",
|
|
},
|
|
});
|
|
|
|
expect(result.langs).toEqual(["typescript"]);
|
|
});
|
|
});
|