mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Highlighting reuses the existing code-block tokenizer and LRU cache, runs lazily on expand, and falls back to plain text above a size cap so a large Read can't stall the main thread. The diff highlighter reconstructs the old and new file text by position rather than from @@ line ranges, so diffs that arrive without real hunk headers still highlight. Read content is normalized server-side: the cat -n line-number gutter some providers emit is stripped so content is uniformly raw source, with the first line number surfaced as offset for the client to rebuild the gutter.
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
extensionFromPath,
|
|
highlightToKeyedLines,
|
|
MAX_HIGHLIGHT_CHARS,
|
|
tokenizeToLines,
|
|
} from "./highlight-cache";
|
|
|
|
describe("extensionFromPath", () => {
|
|
it("extracts a lowercased extension regardless of absolute/relative path", () => {
|
|
expect(extensionFromPath("/repo/src/Index.TS")).toBe("ts");
|
|
expect(extensionFromPath("src/index.ts")).toBe("ts");
|
|
expect(extensionFromPath("a.b/c.tsx")).toBe("tsx");
|
|
});
|
|
|
|
it("returns null for paths without a usable extension", () => {
|
|
expect(extensionFromPath(null)).toBeNull();
|
|
expect(extensionFromPath(undefined)).toBeNull();
|
|
expect(extensionFromPath("Makefile")).toBeNull();
|
|
expect(extensionFromPath(".gitignore")).toBeNull();
|
|
expect(extensionFromPath("trailingdot.")).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("tokenizeToLines", () => {
|
|
it("returns one token array per line for a supported language", () => {
|
|
const lines = tokenizeToLines("const a = 1;\nconst b = 2;", "ts");
|
|
expect(lines).not.toBeNull();
|
|
expect(lines).toHaveLength(2);
|
|
expect(lines?.[0].some((token) => token.style === "keyword")).toBe(true);
|
|
});
|
|
|
|
it("returns null when there is no extension", () => {
|
|
expect(tokenizeToLines("whatever", null)).toBeNull();
|
|
});
|
|
|
|
it("falls back to style-less per-line tokens for an unknown extension", () => {
|
|
const lines = tokenizeToLines("line one\nline two", "unknownext");
|
|
expect(lines).toHaveLength(2);
|
|
expect(lines?.[0]).toEqual([{ text: "line one", style: null }]);
|
|
});
|
|
|
|
it("returns null above the size cap so callers fall back to plain text", () => {
|
|
const huge = "x".repeat(MAX_HIGHLIGHT_CHARS + 1);
|
|
expect(tokenizeToLines(huge, "ts")).toBeNull();
|
|
});
|
|
|
|
it("serves a cached result on repeat calls (identity-stable)", () => {
|
|
const first = tokenizeToLines("const cached = true;", "ts");
|
|
const second = tokenizeToLines("const cached = true;", "ts");
|
|
expect(first).toBe(second);
|
|
});
|
|
});
|
|
|
|
describe("highlightToKeyedLines", () => {
|
|
it("produces stable keys for lines and tokens", () => {
|
|
const keyed = highlightToKeyedLines("const a = 1;", "ts");
|
|
expect(keyed?.[0].key).toBe("line-0");
|
|
expect(keyed?.[0].tokens[0].key).toBe("0-0");
|
|
});
|
|
|
|
it("returns null when highlighting is unavailable", () => {
|
|
expect(highlightToKeyedLines("text", null)).toBeNull();
|
|
});
|
|
});
|