fix(highlight): highlight Svelte components (#3487)
* fix(highlight): highlight Svelte components `.svelte` had no entry in the extension table, so `highlightCode` fell through to one unstyled token per line. That is the same table the file pane, the diff tokens, markdown fences and the web editor all resolve through, so a component rendered as plain text everywhere in the app. Register `@replit/codemirror-lang-svelte`. Its `svelteLanguage` already wires the mixed parsing for the `<script>` and `<style>` blocks, so the script gets JS/TS roles, the style block gets CSS roles, and the template gets tag, directive and mustache roles. It comes from the same publisher as the `@replit/codemirror-lang-csharp` entry already in this package, and only the grammar itself is declared: its CodeMirror peers resolve the same way the C# grammar's peers already do. * test(server): cover Svelte diff highlighting The review surface in the issue is the diff, and the daemon is what tokenizes it (`diff-highlighter.ts` calls `highlightCode`), so the regression belongs here too: script, template block and markup roles on a `.svelte` hunk.
This commit is contained in:
@@ -47,6 +47,7 @@
|
||||
"@lezer/yaml": "^1.0.4",
|
||||
"@replit/codemirror-lang-csharp": "^6.2.0",
|
||||
"@replit/codemirror-lang-nix": "^6.0.1",
|
||||
"@replit/codemirror-lang-svelte": "^6.0.0",
|
||||
"lezer-elixir": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -86,6 +86,38 @@ describe("highlightCode", () => {
|
||||
expect(stringToken?.style).toBe("string");
|
||||
});
|
||||
|
||||
it("highlights Svelte components across script, markup, and style", () => {
|
||||
const code = [
|
||||
'<script lang="ts">',
|
||||
" let count: number = 1;",
|
||||
"</script>",
|
||||
"",
|
||||
"{#if count > 0}",
|
||||
' <span class="badge">{count}</span>',
|
||||
"{/if}",
|
||||
"",
|
||||
"<style>",
|
||||
" .badge {",
|
||||
" color: red;",
|
||||
" }",
|
||||
"</style>",
|
||||
].join("\n");
|
||||
const result = highlightCode(code, "Counter.svelte");
|
||||
|
||||
expect(result[1].find((t) => t.text === "let")?.style).toBe("keyword");
|
||||
expect(result[1].find((t) => t.text === "number")?.style).toBe("type");
|
||||
|
||||
expect(result[4].find((t) => t.text === "if")?.style).toBe("keyword");
|
||||
expect(result[4].find((t) => t.text === "count")?.style).toBe("variable");
|
||||
|
||||
expect(result[5].find((t) => t.text === "span")?.style).toBe("tag");
|
||||
expect(result[5].find((t) => t.text === "class")?.style).toBe("attribute");
|
||||
expect(result[5].find((t) => t.text === "count")?.style).toBe("variable");
|
||||
|
||||
expect(result[9].find((t) => t.text === "badge")?.style).toBe("class");
|
||||
expect(result[10].find((t) => t.text === "color")?.style).toBe("property");
|
||||
});
|
||||
|
||||
it("highlights TSX code with correct dialect", () => {
|
||||
const code = 'const el = <div className="test">hello</div>;';
|
||||
const result = highlightCode(code, "test.tsx");
|
||||
|
||||
@@ -23,6 +23,7 @@ describe("isLanguageSupported", () => {
|
||||
expect(isLanguageSupported("test.cs")).toBe(true);
|
||||
expect(isLanguageSupported("test.nix")).toBe(true);
|
||||
expect(isLanguageSupported("test.ex")).toBe(true);
|
||||
expect(isLanguageSupported("Counter.svelte")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for unsupported file extensions", () => {
|
||||
@@ -63,6 +64,7 @@ describe("getSupportedExtensions", () => {
|
||||
expect(extensions).toContain("cs");
|
||||
expect(extensions).toContain("nix");
|
||||
expect(extensions).toContain("json");
|
||||
expect(extensions).toContain("svelte");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { parser as xmlParser } from "@lezer/xml";
|
||||
import { parser as yamlParser } from "@lezer/yaml";
|
||||
import { csharpLanguage } from "@replit/codemirror-lang-csharp";
|
||||
import { nixLanguage } from "@replit/codemirror-lang-nix";
|
||||
import { svelteLanguage } from "@replit/codemirror-lang-svelte";
|
||||
import { parser as elixirParser } from "lezer-elixir";
|
||||
import type { Parser } from "@lezer/common";
|
||||
|
||||
@@ -49,6 +50,8 @@ const languagesByExtension: Record<string, Language> = {
|
||||
// HTML
|
||||
html: language(htmlParser),
|
||||
htm: language(htmlParser),
|
||||
// Svelte
|
||||
svelte: svelteLanguage,
|
||||
// XML
|
||||
xml: language(xmlParser),
|
||||
// Java
|
||||
|
||||
Reference in New Issue
Block a user