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

feat: replace prism with starry night #67

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,23 +77,6 @@ preference, set the following:

Also see the example application in the `example/` directory.

## Extensibility

By default syntax highlighting for JavaScript, Markdown, and HTML is included.
You can include more languages importing them:

```js
import { CSS, render } from "https://deno.land/x/gfm/mod.ts";

// Add support for TypeScript, Bash, and Rust.
import "https://esm.sh/[email protected]/components/prism-typescript?no-check";
import "https://esm.sh/[email protected]/components/prism-bash?no-check";
import "https://esm.sh/[email protected]/components/prism-rust?no-check";
```

A full list of supported languages is available here:
https://unpkg.com/browse/[email protected]/components/

## Inline rendering

By default, all rendering is in blocks. There are cases where one would like to
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"tasks": {
"build": "deno run --allow-read --allow-write --allow-net --allow-run --allow-env ./style/patch.ts && deno fmt",
"dev": "deno run -A --unstable --watch --no-check ./example/main.ts",
"test": "deno test --allow-read",
"test": "deno test --allow-read --allow-env=VSCODE_TEXTMATE_DEBUG --allow-net=esm.sh",
"coverage": "deno test --allow-read --coverage=cov_profile"
},
"lock": false
Expand Down
7 changes: 6 additions & 1 deletion deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ export { mangle } from "https://esm.sh/[email protected]/";

export { gfmHeadingId } from "https://esm.sh/[email protected]/";

export { default as Prism } from "https://esm.sh/[email protected]";
export {
all,
createStarryNight,
} from "https://esm.sh/@wooorm/[email protected]";

export { toHtml } from "https://esm.sh/[email protected]";

export { default as sanitizeHtml } from "https://esm.sh/[email protected]?target=esnext";

Expand Down
8 changes: 0 additions & 8 deletions example/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ import { serve } from "https://deno.land/[email protected]/http/server.ts";

import { CSS, KATEX_CSS, render } from "../mod.ts";

import "https://esm.sh/[email protected]/components/prism-jsx?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-typescript?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-tsx?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-bash?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-powershell?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-json?no-check&pin=v57";
import "https://esm.sh/[email protected]/components/prism-diff?no-check&pin=v57";

const CONTENT_PATH = new URL("./content.md", import.meta.url);

async function handler(_req: Request): Promise<Response> {
Expand Down
50 changes: 18 additions & 32 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import {
all,
createStarryNight,
emojify,
gfmHeadingId,
htmlEscape,
katex,
mangle,
Marked,
Prism,
sanitizeHtml,
toHtml,
} from "./deps.ts";
import { CSS, KATEX_CLASSES, KATEX_CSS } from "./style.js";
import { CSS, KATEX_CLASSES, KATEX_CSS, STARRY_CLASSES } from "./style.js";
export { CSS, KATEX_CSS, Marked };

const starryNight = await createStarryNight(all);

Marked.marked.use(mangle());
Marked.marked.use(gfmHeadingId());

Expand All @@ -37,6 +41,10 @@ class Renderer extends Marked.Renderer {
}

code(code: string, language?: string) {
if (!language) {
return `<pre><code class="notranslate">${htmlEscape(code)}</code></pre>`;
}

// a language of `ts, ignore` should really be `ts`
// and it should be lowercase to ensure it has parity with regular github markdown
language = language?.split(",")?.[0].toLocaleLowerCase();
Expand All @@ -46,15 +54,14 @@ class Renderer extends Marked.Renderer {
if (language === "math" && this.allowMath) {
return katex.renderToString(code, { displayMode: true });
}
const grammar =
language && Object.hasOwnProperty.call(Prism.languages, language)
? Prism.languages[language]
: undefined;
if (grammar === undefined) {

const scope = starryNight.flagToScope(language);
if (scope === undefined) {
return `<pre><code class="notranslate">${htmlEscape(code)}</code></pre>`;
}
const html = Prism.highlight(code, grammar, language!);
return `<div class="highlight highlight-source-${language} notranslate"><pre>${html}</pre></div>`;
const highlight = starryNight.highlight(code, scope);
const html = toHtml(highlight);
return `<div class="notranslate"><pre>${html}</pre></div>`;
}
link(href: string, title: string | null, text: string) {
const titleAttr = title ? ` title="${title}"` : "";
Expand Down Expand Up @@ -222,30 +229,9 @@ export function render(markdown: string, opts: RenderOptions = {}): string {
annotation: ["encoding"], // Only enabled when math is enabled
},
allowedClasses: {
div: ["highlight", "highlight-source-*", "notranslate"],
div: ["notranslate"],
span: [
"token",
"keyword",
"operator",
"number",
"boolean",
"function",
"string",
"comment",
"class-name",
"regex",
"regex-delimiter",
"tag",
"attr-name",
"punctuation",
"script-punctuation",
"script",
"plain-text",
"property",
"prefix",
"line",
"deleted",
"inserted",
...STARRY_CLASSES,
...(opts.allowMath ? KATEX_CLASSES : []),
],
a: ["anchor"],
Expand Down
38 changes: 37 additions & 1 deletion style.js

Large diffs are not rendered by default.

62 changes: 38 additions & 24 deletions style/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,38 @@ for (const mode of ["light", "dark"]) {

await $`npx parcel build main.scss --no-source-maps`.cwd("./style").quiet();

function extractClasses(cssText: string): string[] {
const CSS_AST = css.parse(cssText);
const CSS_RULES = CSS_AST.stylesheet.rules.filter((
rule: { type: string },
) => rule.type === "rule");
const CSS_SELECTORS = CSS_RULES.reduce(
(acc: string[], cur: { selectors: string[] }) => [...acc, ...cur.selectors],
[],
);

const classRegex = /\.([\w-]+)/g;
const classes: string[] = [];

for (const selector of CSS_SELECTORS) {
let match;
while ((match = classRegex.exec(selector)) !== null) {
classes.push(match[1]);
}
}

// de-duplicate classes
return [...new Set(classes)];
}

// Starry Night

$.logStep("Fetching Starry Night styles");
const STARRY_CSS = (await $.request(
"https://esm.sh/@wooorm/[email protected]/style/both.css",
).text()).split("\n").slice(3).join("");
const STARRY_CLASSES = extractClasses(STARRY_CSS);

// KATEX

$.logStep("Fetching katex styles");
Expand All @@ -57,39 +89,21 @@ let KATEX_CSS = await $.request(`${KATEX_BASE_URL}/katex.min.css`).text();
// Replace url of fonts with a cdn since we aren't packaging these
KATEX_CSS = KATEX_CSS.replaceAll("fonts/", `${KATEX_BASE_URL}/fonts/`);

$.logStep("Extracting katex classes");
const KATEX_CSS_AST = css.parse(KATEX_CSS);
const KATEX_CSS_RULES = KATEX_CSS_AST.stylesheet.rules.filter((
rule: { type: string },
) => rule.type === "rule");
const KATEX_CSS_SELECTORS = KATEX_CSS_RULES.reduce(
(acc: string[], cur: { selectors: string[] }) => [...acc, ...cur.selectors],
[],
);

const classRegex = /\.([\w-]+)/g;
let classes = [];

for (const selector of KATEX_CSS_SELECTORS) {
let match;
while ((match = classRegex.exec(selector)) !== null) {
classes.push(match[1]);
}
}

// de-duplicate classes
classes = [...new Set(classes)];
// Extract classes
const KATEX_CLASSES = extractClasses(KATEX_CSS);

$.logStep("Writing the final style.js");
const CSS = await cwd.join("dist/main.css").textSync();

await cwd.join("../style.js").writeText(
`/** @type {string} */
export const CSS = \`${CSS}\`;
export const CSS = \`${CSS + STARRY_CSS}\`;

export const STARRY_CLASSES = ${JSON.stringify(STARRY_CLASSES)};

/** @type {string} */
export const KATEX_CSS = \`${KATEX_CSS}\`;

export const KATEX_CLASSES = ${JSON.stringify(classes)};
export const KATEX_CLASSES = ${JSON.stringify(KATEX_CLASSES)};
`,
);