GithubHelp home page GithubHelp logo

denoland / deno-gfm Goto Github PK

View Code? Open in Web Editor NEW
209.0 17.0 31.0 395 KB

Server-side GitHub Flavored Markdown rendering for Deno

Home Page: https://deno.land/x/gfm

License: MIT License

TypeScript 98.01% SCSS 1.99%
deno markdown gfm

deno-gfm's Introduction

deno-gfm

Server-side GitHub Flavored Markdown rendering for Deno, including GitHub style CSS, syntax highlighting, and HTML sanitization.

Usage

import { CSS, render } from "jsr:@deno/[email protected]";

const markdown = `
# Hello, world!

| Type | Value |
| ---- | ----- |
| x    | 42    |

\`\`\`js
console.log("Hello, world!");
\`\`\`
`;

const body = render(markdown, {
  baseUrl: "https://example.com",
});

const html = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
      main {
        max-width: 800px;
        margin: 0 auto;
      }
      ${CSS}
    </style>
  </head>
  <body>
    <main data-color-mode="light" data-light-theme="light" data-dark-theme="dark" class="markdown-body">
      ${body}
    </main>
  </body>
</html>
`;

Styling

The GitHub CSS styles (https://primer.style) are used. There are two themes available: light and dark.

There are three data attributes that can be used to control the theme:

  • data-color-mode: light or dark or auto.
  • data-light-theme: the name of the light theme (light or dark).
  • data-dark-theme: the name of the dark theme (light or dark).

For example, if you want to use the dark theme only, set the following:

<div data-color-mode="dark" data-dark-theme="dark" class="markdown-body">
  ... markdown body here ...
</div>

If you want to use the light or dark theme depending on the user's browser preference, set the following:

<div data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" class="markdown-body">
  ... markdown body here ...
</div>

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:

import { CSS, render } from "jsr:@deno/[email protected]";

// Add support for TypeScript, Bash, and Rust.
import "npm:[email protected]/components/prism-typescript.js";
import "npm:[email protected]/components/prism-bash.js";
import "npm:[email protected]/components/prism-rust.js";

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 render some inline markdown, and this is achievable using the inline setting:

import { render } from "jsr:@deno/[email protected]";

const markdown = "My [Deno](https://deno.land) Blog";
const header = render(markdown, { inline: true });
console.log(header);

Math rendering

By default math rendering is disabled. To enable it, you must include the additional CSS and enable the allowMath setting:

import { CSS, KATEX_CSS, render } from "jsr:@deno/[email protected]";

const markdown = `
Block math:

$$ y = x^2 $$

Inline math: $y = x^2$
`;

const body = render(markdown, {
  allowMath: true,
});

const html = `
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
      main {
        max-width: 800px;
        margin: 0 auto;
      }
      ${CSS}
      ${KATEX_CSS}
    </style>
  </head>
  <body>
    <main data-color-mode="light" data-light-theme="light" data-dark-theme="dark" class="markdown-body">
      ${body}
    </main>
  </body>
</html>
`;

deno-gfm's People

Contributors

axelav avatar crowlkats avatar deer avatar dsherret avatar hashrock avatar juanespinola05 avatar kat0h avatar kidonng avatar kitsonk avatar korigamik avatar kt3k avatar leodog896 avatar lino-levan avatar littledivy avatar lj-n avatar lucacasonato avatar marvinhagemeister avatar roj1512 avatar ry avatar tmchein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deno-gfm's Issues

mdx support

Just curious, will there be support for mdx added?

Allow task lists

In routes/index.tsx:

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

const body = render(`# Hello, world!
- Normal list
- [x] #739
- [ ] https://github.com/octo-org/octo-repo/issues/740
- [ ] Add delight to the experience when all tasks are complete :tada:
`);

export default function a() {
    return <main dangerouslySetInnerHTML={{ __html: body }}>
    {body}
    </main>
} 

I expect it to create correct check boxes, not regular list.

About task lists - GitHub Docs

Create custom styles

style.js is a example the custom styles?

export const CSS = `:root,[data-color-mode=light][data-light-theme=light],[data-color-mode=dark][data-dark-theme=light]{--color-canvas-default-transparent:rgba(255,255,255,0);--color-prettylights-syntax-comment:#6e7781;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-entity:#8250df;--color-prettylights-syntax-storage-modifier-import:#24292f;--color-prettylights-syntax-entity-tag:#116329;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#ffebe9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-fg-default:#24292f;--color-fg-muted:#57606a;--color-canvas-default:#fff;--color-canvas-subtle:#f6f8fa;--color-border-default:#d0d7de;--color-border-muted:#d8dee4;--color-neutral-muted:rgba(175,184,193,.2);--color-accent-fg:#0969da;--color-accent-emphasis:#0969da;--color-danger-fg:#cf222e}@media (prefers-color-scheme:light){[data-color-mode=auto][data-light-theme=light]{--color-canvas-default-transparent:rgba(255,255,255,0);--color-prettylights-syntax-comment:#6e7781;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-entity:#8250df;--color-prettylights-syntax-storage-modifier-import:#24292f;--color-prettylights-syntax-entity-tag:#116329;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#ffebe9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-fg-default:#24292f;--color-fg-muted:#57606a;--color-canvas-default:#fff;--color-canvas-subtle:#f6f8fa;--color-border-default:#d0d7de;--color-border-muted:#d8dee4;--color-neutral-muted:rgba(175,184,193,.2);--color-accent-fg:#0969da;--color-accent-emphasis:#0969da;--color-danger-fg:#cf222e}}@media (prefers-color-scheme:dark){[data-color-mode=auto][data-dark-theme=light]{--color-canvas-default-transparent:rgba(255,255,255,0);--color-prettylights-syntax-comment:#6e7781;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-entity:#8250df;--color-prettylights-syntax-storage-modifier-import:#24292f;--color-prettylights-syntax-entity-tag:#116329;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#ffebe9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-fg-default:#24292f;--color-fg-muted:#57606a;--color-canvas-default:#fff;--color-canvas-subtle:#f6f8fa;--color-border-default:#d0d7de;--color-border-muted:#d8dee4;--color-neutral-muted:rgba(175,184,193,.2);--color-accent-fg:#0969da;--color-accent-emphasis:#0969da;--color-danger-fg:#cf222e}}[data-color-mode=light][data-light-theme=dark],[data-color-mode=dark][data-dark-theme=dark]{--color-canvas-default-transparent:rgba(13,17,23,0);--color-prettylights-syntax-comment:#8b949e;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#c9d1d9;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-fg-default:#c9d1d9;--color-fg-muted:#8b949e;--color-canvas-default:#0d1117;--color-canvas-subtle:#161b22;--color-border-default:#30363d;--color-border-muted:#21262d;--color-neutral-muted:rgba(110,118,129,.4);--color-accent-fg:#58a6ff;--color-accent-emphasis:#1f6feb;--color-danger-fg:#f85149}@media (prefers-color-scheme:light){[data-color-mode=auto][data-light-theme=dark]{--color-canvas-default-transparent:rgba(13,17,23,0);--color-prettylights-syntax-comment:#8b949e;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#c9d1d9;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-fg-default:#c9d1d9;--color-fg-muted:#8b949e;--color-canvas-default:#0d1117;--color-canvas-subtle:#161b22;--color-border-default:#30363d;--color-border-muted:#21262d;--color-neutral-muted:rgba(110,118,129,.4);--color-accent-fg:#58a6ff;--color-accent-emphasis:#1f6feb;--color-danger-fg:#f85149}}@media (prefers-color-scheme:dark){[data-color-mode=auto][data-dark-theme=dark]{--color-canvas-default-transparent:rgba(13,17,23,0);--color-prettylights-syntax-comment:#8b949e;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#c9d1d9;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-fg-default:#c9d1d9;--color-fg-muted:#8b949e;--color-canvas-default:#0d1117;--color-canvas-subtle:#161b22;--color-border-default:#30363d;--color-border-muted:#21262d;--color-neutral-muted:rgba(110,118,129,.4);--color-accent-fg:#58a6ff;--color-accent-emphasis:#1f6feb;--color-danger-fg:#f85149}}.markdown-body{word-wrap:break-word;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;font-size:16px;line-height:1.5}.markdown-body:before{content:"";display:table}.markdown-body:after{clear:both;content:"";display:table}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:var(--color-danger-fg)}.markdown-body .anchor{float:left;margin-left:-20px;padding-right:4px;line-height:1}.markdown-body .anchor:focus{outline:none}.markdown-body p,.markdown-body blockquote,.markdown-body ul,.markdown-body ol,.markdown-body dl,.markdown-body table,.markdown-body pre,.markdown-body details{margin-top:0;margin-bottom:16px}.markdown-body hr{height:.25em;background-color:var(--color-border-default);border:0;margin:24px 0;padding:0}.markdown-body blockquote{color:var(--color-fg-muted);border-left:.25em solid var(--color-border-default);padding:0 1em}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{font-weight:var(--base-text-weight-semibold,600);margin-top:24px;margin-bottom:16px;line-height:1.25}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:var(--color-fg-default);vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 tt,.markdown-body h1 code,.markdown-body h2 tt,.markdown-body h2 code,.markdown-body h3 tt,.markdown-body h3 code,.markdown-body h4 tt,.markdown-body h4 code,.markdown-body h5 tt,.markdown-body h5 code,.markdown-body h6 tt,.markdown-body h6 code{font-size:inherit;padding:0 .2em}.markdown-body h1{border-bottom:1px solid var(--color-border-muted);padding-bottom:.3em;font-size:2em}.markdown-body h2{border-bottom:1px solid var(--color-border-muted);padding-bottom:.3em;font-size:1.5em}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:.875em}.markdown-body h6{color:var(--color-fg-muted);font-size:.85em}.markdown-body summary h1,.markdown-body summary h2,.markdown-body summary h3,.markdown-body summary h4,.markdown-body summary h5,.markdown-body summary h6{display:inline-block}.markdown-body summary h1 .anchor,.markdown-body summary h2 .anchor,.markdown-body summary h3 .anchor,.markdown-body summary h4 .anchor,.markdown-body summary h5 .anchor,.markdown-body summary h6 .anchor{margin-left:-40px}.markdown-body summary h1,.markdown-body summary h2{border-bottom:0;padding-bottom:0}.markdown-body ul,.markdown-body ol{padding-left:2em}.markdown-body ul.no-list,.markdown-body ol.no-list{padding:0;list-style-type:none}.markdown-body ol[type=a]{list-style-type:lower-alpha}.markdown-body ol[type=A]{list-style-type:upper-alpha}.markdown-body ol[type=i]{list-style-type:lower-roman}.markdown-body ol[type=I]{list-style-type:upper-roman}.markdown-body ol[type="1"]{list-style-type:decimal}.markdown-body div>ol:not([type]){list-style-type:decimal}.markdown-body ul ul,.markdown-body ul ol,.markdown-body ol ol,.markdown-body ol ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{margin-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{font-size:1em;font-style:italic;font-weight:var(--base-text-weight-semibold,600);margin-top:16px;padding:0}.markdown-body dl dd{margin-bottom:16px;padding:0 16px}.markdown-body table{width:100%;width:-webkit-max-content;width:-webkit-max-content;width:max-content;max-width:100%;display:block;overflow:auto}.markdown-body table th{font-weight:var(--base-text-weight-semibold,600)}.markdown-body table th,.markdown-body table td{border:1px solid var(--color-border-default);padding:6px 13px}.markdown-body table tr{background-color:var(--color-canvas-default);border-top:1px solid var(--color-border-muted)}.markdown-body table tr:nth-child(2n){background-color:var(--color-canvas-subtle)}.markdown-body table img{background-color:transparent}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:var(--color-canvas-default)}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{max-width:none;vertical-align:text-top;background-color:transparent}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{float:left;width:auto;border:1px solid var(--color-border-default);margin:13px 0 0;padding:7px;display:block;overflow:hidden}.markdown-body span.frame span img{float:left;display:block}.markdown-body span.frame span span{clear:both;color:var(--color-fg-default);padding:5px 0 0;display:block}.markdown-body span.align-center{clear:both;display:block;overflow:hidden}.markdown-body span.align-center>span{text-align:center;margin:13px auto 0;display:block;overflow:hidden}.markdown-body span.align-center span img{text-align:center;margin:0 auto}.markdown-body span.align-right{clear:both;display:block;overflow:hidden}.markdown-body span.align-right>span{text-align:right;margin:13px 0 0;display:block;overflow:hidden}.markdown-body span.align-right span img{text-align:right;margin:0}.markdown-body span.float-left{float:left;margin-right:13px;display:block;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{float:right;margin-left:13px;display:block;overflow:hidden}.markdown-body span.float-right>span{text-align:right;margin:13px auto 0;display:block;overflow:hidden}.markdown-body code,.markdown-body tt{white-space:break-spaces;background-color:var(--color-neutral-muted);border-radius:6px;margin:0;padding:.2em .4em;font-size:85%}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}.markdown-body samp{font-size:85%}.markdown-body pre{word-wrap:normal}.markdown-body pre code{font-size:100%}.markdown-body pre>code{word-break:normal;white-space:pre;background:0 0;border:0;margin:0;padding:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{word-break:normal;margin-bottom:0}.markdown-body .highlight pre,.markdown-body pre{background-color:var(--color-canvas-subtle);border-radius:6px;padding:16px;font-size:85%;line-height:1.45;overflow:auto}.markdown-body pre code,.markdown-body pre tt{max-width:auto;line-height:inherit;word-wrap:normal;background-color:transparent;border:0;margin:0;padding:0;display:inline;overflow:visible}.markdown-body .csv-data td,.markdown-body .csv-data th{text-align:left;white-space:nowrap;padding:5px;font-size:12px;line-height:1;overflow:hidden}.markdown-body .csv-data .blob-num{text-align:right;background:var(--color-canvas-default);border:0;padding:10px 8px 9px}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:var(--base-text-weight-semibold,600);background:var(--color-canvas-subtle);border-top:0}.markdown-body [data-footnote-ref]:before{content:"["}.markdown-body [data-footnote-ref]:after{content:"]"}.markdown-body .footnotes{color:var(--color-fg-muted);border-top:1px solid var(--color-border-default);font-size:12px}.markdown-body .footnotes ol{padding-left:16px}.markdown-body .footnotes ol ul{margin-top:16px;padding-left:16px;display:inline-block}.markdown-body .footnotes li{position:relative}.markdown-body .footnotes li:target:before{pointer-events:none;content:"";border:2px solid var(--color-accent-emphasis);border-radius:6px;position:absolute;top:-8px;bottom:-8px;left:-24px;right:-8px}.markdown-body .footnotes li:target{color:var(--color-fg-default)}.markdown-body .footnotes .data-footnote-backref g-emoji{font-family:monospace}.markdown-body{background-color:var(--color-canvas-default);color:var(--color-fg-default)}.markdown-body a{color:var(--color-accent-fg);text-decoration:none}.markdown-body a:hover{text-decoration:underline}.markdown-body img[align=center]{margin:0 auto}.markdown-body iframe{background-color:#fff;border:0;margin-bottom:16px}.markdown-body svg.octicon{fill:currentColor}.markdown-body .anchor>.octicon{display:inline}.markdown-body figcaption{text-align:center;padding-top:2px}.markdown-body .highlight .token.keyword,.gfm-highlight .token.keyword{color:var(--color-prettylights-syntax-keyword)}.markdown-body .highlight .token.tag .token.class-name,.markdown-body .highlight .token.tag .token.script .token.punctuation,.gfm-highlight .token.tag .token.class-name,.gfm-highlight .token.tag .token.script .token.punctuation{color:var(--color-prettylights-syntax-storage-modifier-import)}.markdown-body .highlight .token.operator,.markdown-body .highlight .token.number,.markdown-body .highlight .token.boolean,.markdown-body .highlight .token.tag .token.punctuation,.markdown-body .highlight .token.tag .token.script .token.script-punctuation,.markdown-body .highlight .token.tag .token.attr-name,.gfm-highlight .token.operator,.gfm-highlight .token.number,.gfm-highlight .token.boolean,.gfm-highlight .token.tag .token.punctuation,.gfm-highlight .token.tag .token.script .token.script-punctuation,.gfm-highlight .token.tag .token.attr-name{color:var(--color-prettylights-syntax-constant)}.markdown-body .highlight .token.function,.gfm-highlight .token.function{color:var(--color-prettylights-syntax-entity)}.markdown-body .highlight .token.string,.gfm-highlight .token.string{color:var(--color-prettylights-syntax-string)}.markdown-body .highlight .token.comment,.gfm-highlight .token.comment{color:var(--color-prettylights-syntax-comment)}.markdown-body .highlight .token.class-name,.gfm-highlight .token.class-name{color:var(--color-prettylights-syntax-variable)}.markdown-body .highlight .token.regex,.gfm-highlight .token.regex{color:var(--color-prettylights-syntax-string)}.markdown-body .highlight .token.regex .regex-delimiter,.gfm-highlight .token.regex .regex-delimiter{color:var(--color-prettylights-syntax-constant)}.markdown-body .highlight .token.tag .token.tag,.markdown-body .highlight .token.property,.gfm-highlight .token.tag .token.tag,.gfm-highlight .token.property{color:var(--color-prettylights-syntax-entity-tag)}.markdown-body .highlight .token.deleted,.gfm-highlight .token.deleted{color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}.markdown-body .highlight .token.inserted,.gfm-highlight .token.inserted{color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}`;

Becasuse style.js doesn`t support all markdown

Or am i doing it wrong

Add support for links that reference the working directory with a baseUrl

There are cases where a link uses dot notation, referencing the working directory.

eg:

const link = './useHead.mjs'
const baseUrl = 'https://deno.land/x/[email protected]'

In this case with the current link treatment, the result of the link will be:

const linkAfterGfm =  'https://deno.land/x/useHead.mjs'

generating issues as shown in Relative URLs in readme markdown starting with ./ render broken ยท Issue #2060 ยท denoland/dotland

/x does not render text as bold if followed by a hard line-break

It's entirely possible this bug is upstream.

Repro

The markup

- **Breaking: Changed how clients are instantiated with an API (#0)**\
  The API object must now be passed in as an api property on an object.

How GitHub renders it

  • Breaking: Changed how clients are instantiated with an API (#0)
    The API object must now be passed in as an api property on an object.

And on deno.land/x

image

Interestingly it seems to only affect lines that end with a non-alphanumeric character, but I haven't tested further.
image

Allow alert/callout

From Basic writing and formatting syntax - GitHub Docs:

Alerts are a Markdown extension based on the blockquote syntax that you can use to emphasize critical information. On GitHub, they are displayed with distinctive colors and icons to indicate the significance of the content.

Use alerts only when they are crucial for user success and limit them to one or two per article to prevent overloading the reader. Additionally, you should avoid placing alerts consecutively. Alerts cannot be nested within other elements.

To add an alert, use a special blockquote line specifying the alert type, followed by the alert information in a standard blockquote. Five types of alerts are available:

> [!NOTE]
> Useful information that users should know, even when skimming content.

> [!TIP]
> Helpful advice for doing things better or more easily.

> [!IMPORTANT]
> Key information users need to know to achieve their goal.

> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.

> [!CAUTION]
> Advises about risks or negative outcomes of certain actions.

Here are the rendered alerts:

Add an option for hard line breaks

I expected this markdown text:

From fairest creatures we desire increase,
That thereby beautyโ€™s rose might never die,
But as the riper should by time decrease,
His tender heir mught bear his memeory:

to be rendered like this (as the same as on GitHub):

From fairest creatures we desire increase,
That thereby beautyโ€™s rose might never die,
But as the riper should by time decrease,
His tender heir mught bear his memeory:

However it is actually rendered like this:

From fairest creatures we desire increase, That thereby beautyโ€™s rose might never die, But as the riper should by time decrease, His tender heir mught bear his memeory:

Meanwhile, I hope deno-gfm will have a rendering option for line breaks as so-called hard line breaks.

const body = render(markdown, {
  hardLineBreaks: true,
});

Thanks!

Write actual docs

Currently, this project has essentially no documentation outside of the readme and (maybe?) some jsdoc comments. Ideally we have docs with examples. I will obviously push for using pyro for this but in theory given that it would just be markdown we could really use anything.

Dependency deprecation warning for `baseUrl`

When using render() with baseUrl prop I get the following warning:

marked(): baseUrl parameter is deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-base-url.

I guess this is fixable in the same way as #70.

How to embed image?

On static folder I have a cover.png image. In routes/index.tsx I have:

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

const body = render(`# Hello, world!
![](../static/cover.png)
![](./static/cover.png)
![](/static/cover.png)
![](static/cover.png)
`);

export default function a() {
    return <main dangerouslySetInnerHTML={{ __html: body }}>
    {body}
    </main>
} 

There is no image. Why is that?

Allow custom HTML

I would like this code to render my custom marker. I don't want to style everything in the style.css.

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

const body = render(`# Hello, world!
<ul style="list-style-type: '&#x1F514; ';">
    <li>item</li>
    <li>item</li>
    <li>item</li>
</ul>

- Normal list
- Normal list
- Normal list
`);

export default function a() {
    return <main dangerouslySetInnerHTML={{ __html: body }}>
    {body}
    </main>
} 

All left angle brackets are HTML encoded?

routes/_app.tsx:

import { type PageProps } from "$fresh/server.ts";
export default function App({ Component }: PageProps) {
  return (
        <Component />
  );
}

routes/test.tsx:

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

const markdown = `# Hello, world!`

const body = render(markdown, {
  baseUrl: "https://example.com",
});

export default function a() {
    return <main data-color-mode="light" data-light-theme="light" data-dark-theme="dark" class="markdown-body">
    {body}
    </main>
} 

Result:
<!DOCTYPE html><html><head><title>fresh-project2</title><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><link rel="stylesheet" href="[/styles.css](view-source:http://localhost:8000/styles.css)"/><script src="[/_frsh/fresh_dev_client.js](view-source:http://localhost:8000/_frsh/fresh_dev_client.js)" nonce="dd12d46ea6e34fee90f20e87b35e0ec6" type="module"></script></head><body><main data-color-mode="light" data-light-theme="light" data-dark-theme="dark" class="markdown-body">&lt;h1 id=&quot;hello-world&quot;>&lt;a class=&quot;anchor&quot; aria-hidden=&quot;true&quot; tabindex=&quot;-1&quot; href=&quot;#hello-world&quot;>&lt;svg class=&quot;octicon octicon-link&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot; height=&quot;16&quot; aria-hidden=&quot;true&quot;>&lt;path fill-rule=&quot;evenodd&quot; d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot;>&lt;/path>&lt;/svg>&lt;/a>Hello, world!&lt;/h1></main></body></html>

Is there anything I did wrong?

What is the current scope of this project?

Pin @hashrock since you have recently worked on this.

With #5 implemented and interests in #28, I think this project is going beyond the definition of "GitHub Flavored Markdown" (GFM), heading towards "Markup features supported by GitHub".

I'm not saying this is a bad thing, but we need to make things clear. This project, in its current form, is no longer just a GFM renderer (in which case, one would probably be better using micromark or remark). The description should be changed to something like "Server-side GitHub-style Markdown rendering for Deno".

And we need to draw the line somewhere. For example, the GitHub feature mentioned in #46 in too niche to have it here.

Needs CI

This is used in many places and has added features that are not in marked, so I think it's time for a unit test and CI.

Switch to a CommonMark compliant parser

Marked is not CommonMark compliant. It has improved significantly since I last looked at it, but there are still a few edge cases.

I suggest switching to a CommonMark compliant parser if deno-gfm is aiming for feature parity with GitHub.

There are a few choices:

  • remark: the most obvious choice. For starters, remark-gfm solves #6 with zero efforts.
  • markdown-it: maintenance seems to be stalled, and I cannot fathom why VitePress chooses it if it's starting anew.
  • marked: believe it is already good enough and will eventually be compliant

I won't dive deep here because remark people has written awesome comparisons.

Personally I'm strongly in favor of remark, it makes future development easier than the other choices.

Tags not updated

The latest tag 0.2.0 doesn't have some of the newer commits.
Consider updating the tag.

Dependency Deprecation Warning

Hello there! ๐Ÿ‘‹

I noticed a deprecation warning in the module's dependency, marked(). The warning states that the mangle parameter is deprecated since version 5.0.0 and should not be used. Instead, it recommends using the npm package marked-mangle.

I kindly request the maintainers to consider updating the dependency, as suggested in the deprecation warning. This change will ensure the continued compatibility and stability of the module for Deno users.

Warning

marked(): mangle parameter is deprecated since version 5.0.0, should not be used and will be removed in the future. Instead use https://www.npmjs.com/package/marked-mangle.

Whitelist various html5 tags

I'd like to see these html5 tags whitelisted, so we can target them in gfm.css.ts.

<cite>, <mark>, <acronym>, <abbr>, <address>, <ins>, <del>, <details> and <summary, <meter>

The <meter> tag is good for indicating how much of something, so you could show your skill level in a topic, in a resume for instance.

X Skill: <meter optimum="40" high="80" max="100" value="20">85%</meter>

A highlight class in a div is already whitelisted, so, you can do like this in gfm.css.ts:

.markdown-body .highlight {
  background: azure;
}

And add this to your markdown file for a "poor man's callout":

<div class="highlight"><strong>Note:</strong> Some text like a warning or tip, you want to emphasize... </div>

Interactivity

I'd like to place an island inside my GFM content. I'm exploring MDX but I'm wondering if deno-gfm can already do this or if such is on the roadmap.

Fenced code blocks are missing their language attributes

given the input

```css
.example {
  color: hotpink;
}
\```

renders out as

<div class="highlight notranslate"><pre>...</pre></div>

regardless of the presence of the language after the triple backticks. Even importing various languages like import 'https://esm.sh/prismjs/components/prism-css' don't change the rendered output.

Rendering bug with dollar signs in tables

| 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   |

Renders like this:

image

Weirdly enough, deleting the space between the first pipe and the dollar sign in each row fixes it:

| 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   |

image

Remove marked-mangle as it doesn't work

Even though marked-mangle is loaded with use, it doesn't seem to work.

The expected behavior is this test should pass:

Deno.test("Email should mangled",  () => {
  const markdown = "[email protected]";
  const expected =
    `<p><a href="mailto:&#101;&#109;&#97;&#x69;&#x6c;&#x40;&#101;&#120;&#x61;&#x6d;&#x70;&#x6c;&#x65;&#46;&#x63;&#x6f;&#109;">&#101;&#109;&#97;&#x69;&#x6c;&#x40;&#101;&#120;&#x61;&#x6d;&#x70;&#x6c;&#x65;&#46;&#x63;&#x6f;&#109;</a></p>\n`;
  const html = render(markdown);
  assertEquals(html, expected);
});

Consider "shortcuts" for use in markdown files

I notice that @lucacasonato's freshworkshop and the fresh docs both use deno-gfm.

I see that fresh docs have a custom gfm.css.ts file for customizing styles, so we get a bit of customizability working with the tags inside the rendered markdown area.

Some markdown engines, especially SSG's in particular, let you define "shortcuts" that are then parsed into something that has a bit complicated HTML structure like a "callout" which might be structured as such, but its html defined elsewhere:

{% callout title="Tip!" %}
This is the body of the tip with a [markdown link](/some/url/path).
{% /callout %}

Does this kind of thing exist in gfm? If not, it would be a great addition.

katex types seemingly not cacheable

I've tried using this lib in both a plain Deno script and in a Deno Fresh project. In every run / watch-triggered reload, I see the following re-download: https://esm.sh/v113/@types/[email protected] 6.0/dist/katex.mjs~.d.ts. Life could be worse... it takes barely 5 seconds. Still, would be good to look into this dep / enabling its caching.

Write more tests

PR welcome!

  • transformMedia
  • allowIframes
  • disableHtmlSanitization
  • code block
  • browser tests - mainly CSS

I'm not looking to get coverage to 100%, but I'd like to get it to over 80%. you can check it by deno task coverage and deno coverage ./cov_profile

Stop building CSS and adopt `github-markdown-css` instead

github-markdown-css was initially suggested as an attempt to reduce bundle size in #2, but at that time I feel this could result in being neglected.

Now that this project is under denoland umbrella and getting proper maintenance, it makes sense to ask: Is bundling CSS necessary? Won't that be too opinionated?

I think it would better to focus on the actual rendering, and dedicate styling to people who are doing it seriously in a standalone object.

This also covers the recently added Katex styles, which is a opt-in feature to begin with.

It may look inconvenient as one has to fetch the style themselves, but I consider this a push for the good: you should use <link rel="stylesheet"> instead of inlining this many styles after all.

title="null" with disableHtmlSanitization: true

Report on twitter

https://twitter.com/kebsworld/status/1652289518249099270
image

Minimal Reproduction

script:

import { render } from "https://deno.land/x/[email protected]/mod.ts";
const body = "[hello](https://example.com/) World";
const html = render(body, {
  disableHtmlSanitization: true,
});
console.log(html);

result:

<p><a href="https://example.com/" title="null" rel="noopener noreferrer">hello</a> World</p>

But not reproduced with no option:

script:

import { render } from "https://deno.land/x/[email protected]/mod.ts";
const body = "[hello](https://example.com/) World";
const html = render(body);
console.log(html);

result:

<p><a href="https://example.com/" rel="noopener noreferrer">hello</a> World</p>

Uncaught TypeError: Cannot convert object to primitive value

> deno run --reload https://deno.land/x/[email protected]/example/main.ts
error: Uncaught TypeError: Cannot convert object to primitive value
    at String (<anonymous>)
    at Ft (https://esm.sh/v88/[email protected]/deno/htmlparser2.js:3:20007)
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:3:21160
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:3:22507
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:2:1107
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:3:25511
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:2:1107
    at https://esm.sh/v88/[email protected]/deno/htmlparser2.js:3:25658

yaml parsing does not work

I am able to successfully parse and highlight other languages, but yaml does not parse correctly. It parses "successfully", but the output is missing important decoration. The most visible issue is that key's are not marked as such.

Example Markdown (Ignore the slash, it is needed to stop github from breaking here, but the actual examples are valid)

\```yaml
name: test
checks:
    prop: "a"
    list:
        - first
        - second
\```

Expected Output

Here is an example from the prism playground. The output has keys marked with a key class

image

Actual Output

However, this library does not apply that class.

Example Code:

import { serve } from "https://deno.land/[email protected]/http/server.ts";
import { default as html } from "https://deno.land/x/[email protected]/html.tsx";
import { render } from "https://deno.land/x/gfm/mod.ts";
import 'https://esm.sh/[email protected]/components/prism-yaml'


const markdown = `
# Demo

A YAML parsing Test

\`\`\`yaml
name: test
checks:
    prop: "a"
    list:
        - first
        - second
\`\`\`
`;

serve((req: Request) => html(render(markdown)));

Links:

image

Notice the missing key class. Without this, the highlighting is missing nearly all colors.

Consider supporting inline markdown

Inline markdown could be useful for lightweight markup on blog post titles, and it could be implemented easily with Marked's parseInline function.

Slow load times

Upon every run of any script that uses gfm the following 2 files are being downloaded.
This is especially annoying when reloading the scripts and causes the projects hosted on deno.dev to have slow startup times.

test/deno-gfm git:(main) โ–ถ deno task dev
Task dev deno run -A --unstable --watch --no-check ./example/main.ts
Watcher Process started.
Download https://esm.sh/v106/@types/[email protected]/dist/katex.mjs~.d.ts (0/2)

What causes this unnecessary types downloading and how can it be avoided?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.