Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: yaml is correctly highlighted #96

Merged
merged 8 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dev": "deno run -A --unstable --watch --no-check ./example/main.ts",
"ok": "deno fmt --check && deno lint && deno task check:types && deno task test",
"report": "deno coverage cov_profile --html",
"server": "deno run -A --watch=test/,mod.ts ./test/runTestServer.ts",
"test": "deno test --allow-read --allow-env --allow-write --allow-run --allow-net"
},
"fmt": {
Expand Down
3 changes: 3 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "./deps.ts";
import { CSS, KATEX_CLASSES, KATEX_CSS } from "./style.js";
export { CSS, KATEX_CSS, Marked };
import "https://esm.sh/[email protected]/components/prism-yaml";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is pulling in yaml for everyone necessary? It seems like the actual fix is the additional types below. Won't that still work if the user app pulls in YAML (like it has to pull in most languages)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly I think it is. The necessary thing is making sure this returns something:

const grammar =

The only way I could do that is by importing the package. For whatever reason I couldn't find any way to invoke the loadlanguages function that prism has.


Marked.marked.use(markedAlert());
Marked.marked.use(gfmHeadingId());
Expand Down Expand Up @@ -231,6 +232,8 @@ export function render(markdown: string, opts: RenderOptions = {}): string {
"line",
"deleted",
"inserted",
"key",
"atrule",
...(opts.allowMath ? KATEX_CLASSES : []),
],
a: ["anchor"],
Expand Down
2 changes: 1 addition & 1 deletion style.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions style/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@
color: var(--color-prettylights-syntax-constant);
}

&.atrule {
color: var(--color-prettylights-syntax-keyword);
}

&.punctuation {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You added key to the options above, but didn't add a matching style. Was that intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the css produced purely by prism is also lacking css for this, although I could be wrong. Is it the styling looking incorrect?

color: var(--color-prettylights-syntax-entity);
}

&.function {
color: var(--color-prettylights-syntax-entity);
}
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/yaml.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<div class="highlight highlight-source-yaml notranslate"><pre><span class="token key atrule">name</span><span class="token punctuation">:</span> test
<span class="token key atrule">checks</span><span class="token punctuation">:</span>
<span class="token key atrule">prop</span><span class="token punctuation">:</span> <span class="token string">"a"</span>
<span class="token key atrule">list</span><span class="token punctuation">:</span>
<span class="token punctuation">-</span> first
<span class="token punctuation">-</span> second</pre></div>
8 changes: 8 additions & 0 deletions test/fixtures/yaml.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```yaml
name: test
checks:
prop: "a"
list:
- first
- second
```
2 changes: 2 additions & 0 deletions test/runTestServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import { startServer } from "./test_utils.ts";
startServer();
46 changes: 29 additions & 17 deletions test/server_test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
import { assert } from "./test_deps.ts";
import { render } from "../mod.ts";
import { browserTest, setupHtmlWithCss } from "./test_utils.ts";
import { assert, assertEquals } from "./test_deps.ts";
import { browserTest } from "./test_utils.ts";

Deno.test("basic md table with dollar signs", async () => {
const markdown = `| Fruit Name | Quantity | Unit Cost per Item | Subtotal |
|------------|----------|--------------------|----------|
| Apple | 1 | $1.50 | $1.50 |
| Pear | 2 | $2.00 | $4.00 |
| Orange | 3 | $2.50 | $7.50 |
| Grape | 60 | $0.05 | $3.00 |
| Total | | | $16.00 |`;

const body = render(markdown);
const html = setupHtmlWithCss(body);

await browserTest(html, async (page, address) => {
await page.goto(`${address}`);

await browserTest("basicMarkdownTable", async (page) => {
await page.waitForSelector("table", { timeout: 1000 });
const tableExists = await page.evaluate(() => {
const table = document.querySelector("table");
Expand Down Expand Up @@ -91,3 +77,29 @@ Deno.test("basic md table with dollar signs", async () => {
);
});
});

Deno.test("yaml style", async () => {
await browserTest("yaml", async (page) => {
const nameStyle = await page.evaluate(() => {
const element = document.querySelector(
"body > main > div > pre > span:nth-child(1)",
);
if (element) {
return window.getComputedStyle(element).color;
}
return null;
});
assertEquals(nameStyle, "rgb(207, 34, 46)");

const colonStyle = await page.evaluate(() => {
const element = document.querySelector(
"body > main > div > pre > span:nth-child(2)",
);
if (element) {
return window.getComputedStyle(element).color;
}
return null;
});
assertEquals(colonStyle, "rgb(102, 57, 186)");
});
});
8 changes: 8 additions & 0 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,11 @@ Deno.test("expect console warning from invalid math", () => {

console.warn = originalWarn;
});

Deno.test("yaml unit", () => {
const markdown = Deno.readTextFileSync("./test/fixtures/yaml.md");
const expected = Deno.readTextFileSync("./test/fixtures/yaml.html");

const html = render(markdown);
assertEquals(html, expected);
});
69 changes: 56 additions & 13 deletions test/test_utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
import { Page, puppeteer } from "./test_deps.ts";
import { CSS } from "../mod.ts";
import { CSS, render, RenderOptions } from "../mod.ts";

type TestCase = {
markdown: string;
renderOptions?: RenderOptions;
};

export type TestCases = "basicMarkdownTable" | "yaml";

export const testCases: Record<TestCases, TestCase> = {
"basicMarkdownTable": {
markdown: `| Fruit Name | Quantity | Unit Cost per Item | Subtotal |
|------------|----------|--------------------|----------|
| Apple | 1 | $1.50 | $1.50 |
| Pear | 2 | $2.00 | $4.00 |
| Orange | 3 | $2.50 | $7.50 |
| Grape | 60 | $0.05 | $3.00 |
| Total | | | $16.00 |`,
},
"yaml": {
markdown: Deno.readTextFileSync("./test/fixtures/yaml.md"),
},
};

export async function browserTest(
htmlContent: string,
fn: (page: Page, address: string) => Promise<void>,
port = 8000,
test: TestCases,
fn: (page: Page) => Promise<void>,
) {
const { serverProcess, address } = await startServer(htmlContent, port);
const { serverProcess, address } = await startServer();

try {
const browser = await puppeteer.launch({
Expand All @@ -16,7 +37,8 @@ export async function browserTest(

try {
const page = await browser.newPage();
await fn(page, address);
await page.goto(`${address}/${test}`);
await fn(page);
} finally {
await browser.close();
}
Expand All @@ -25,22 +47,31 @@ export async function browserTest(
}
}

function startServer(htmlContent: string, port: number) {
const serverProcess = Deno.serve({ port }, (_req) => {
export function startServer() {
const serverProcess = Deno.serve((req) => {
const route = req.url.replace("http://localhost:8000/", "");
let body = "";
if (isTestCase(route)) {
const testCase = testCases[route];
body = render(testCase.markdown, testCase.renderOptions);
} else if (route === "") {
body = render(generateIndexMarkdown());
} else {
throw new Error("Invalid route specified");
}
const htmlContent = wrapBody(body);

return new Response(htmlContent, {
headers: { "Content-Type": "text/html" },
});
});

const hostname = "localhost";
const address = `http://${hostname}:${port}`;

console.log(`Server running at ${address}`);
const address = `http://localhost:8000`;

return { serverProcess, address };
}

export function setupHtmlWithCss(bodyContent: string): string {
function wrapBody(bodyContent: string) {
return `<!DOCTYPE html>
<html lang="en">
<head>
Expand All @@ -62,3 +93,15 @@ export function setupHtmlWithCss(bodyContent: string): string {
</html>
`;
}

function generateIndexMarkdown() {
let markdown = "# Deno GFM Server Tests\n";
markdown += Object.keys(testCases).map((testCase) => {
return `- [${testCase}](http://localhost:8000/${testCase})`;
}).join("\n");
return markdown;
}

function isTestCase(route: string): route is TestCases {
return route in testCases;
}