
# Markdown to HTML Converter

This project pulls together a number of other projects, along with some custom extensions, to provide rendering to HTML for a custom, extended version of Markdown.

These are the primary projects used to render various types of content:

- [Marked](https://marked.js.org/)
- [Prism.js](https://prismjs.com/)
- [Vega](https://vega.github.io/vega/)
- [nomnoml](https://www.nomnoml.com/)
- [bytefield-svg](https://bytefield-svg.deepsymmetry.org/bytefield-svg/1.6.1/intro.html)
- [Katex](https://katex.org/)
- [Pikchr](https://pikchr.org/home/doc/trunk/homepage.md)
- [node-qrcode](https://github.com/soldair/node-qrcode)



## Install from npm

```bash
# Update project npm config to refer to correct registry for the @doc-utils scope
echo '@doc-utils:registry=https://gitea.jbrumond.me/api/packages/doc-utils/npm/' >> ./.npmrc

# Install package for programatic use
npm install --save @doc-utils/markdown2html

# Install globally for CLI usage
npm install --global @doc-utils/markdown2html
```



## Building from source

```bash
npm run tsc
```



## Programatic Use

```ts
import { MarkdownOptions, render_markdown_to_html } from '@doc-utils/markdown2html';

async function main() {
  const options: MarkdownOptions = {
    base_url: 'https://example.com',
  };

  const html = await render_markdown_to_html('# This is some markdown', options);
}
```

### Handling front matter

```ts
import { process_frontmatter } from '@doc-utils/markdown2html';

const raw_content = `---
title: Example Markdown with front matter
foo:
- bar
- baz
---

# This is some markdown
`;

const { frontmatter, document } = process_frontmatter(raw_content);

console.log(frontmatter.title);  // "Example Markdown with front matter"
console.log(frontmatter.foo);    // [ "bar", "baz" ]
console.log(document);           // "\n# This is some markdown\n"
```



## Command Line Use

```bash
echo '# This is some markdown' | ./bin/markdown2html --base-url 'https://example.com' > output.html
```

### Handling front matter

```bash
filecontents="---
title: Example Markdown with front matter
foo:
- bar
- baz
---

# This is some markdown
"

echo "$filecontents" | ./bin/strip-frontmatter frontmatter.json > markdown.md
```



## Options

- `options.base_url` / `--base-url` - Sets the Marked `baseUrl` option
- `options.breaks` / `--breaks` - Sets the Marked `breaks` option
- `options.inline` / `--inline` - Sets the Marked `inline` option
- `options.katex_macros` / `--katex-macro` - Defines any global Katex macros to be used.
- `options.extensions` - Any additional Marked extension factories to use

#### Katex Macro Examples

```ts
const options: MarkdownOptions = {
  katex_macros: {
    '\\foobar': '\\text{foo} + \\text{bar}',
    '\\bazqux': '\\text{baz} + \\text{qux}',
  }
};
```

```bash
./bin/markdown2html \
  --katex-macro '\foobar' '\text{foo} + \text{bar}' \
  --katex-macro '\bazqux' '\text{baz} + \text{qux}'
```




## Extensions

```ts
// extension.ts
import type { marked } from 'marked';
import type { MarkdownOptions } from '@doc-utils/markdown2html';

export interface MyCustomToken extends marked.Tokens.Generic {
  // ...
}

export function my_extension(renderer: marked.Renderer, options: MarkdownOptions) : marked.TokenizerExtension & marked.RendererExtension {
  return {
    name: 'my_extension',
    level: 'inline',
    start: (src) => src.match(/...../)?.index,
    tokenizer(src, tokens) : MyCustomToken {
      const rule = /...../;
      const match = rule.exec(src);

      if (match) {
        return {
          // ...
        };
      }
    },
    renderer(token: MyCustomToken) {
      return '<!-- rendered html -->';
    }
  };
};



// ----------

// main.ts
import { my_extension } from './extension';
import { MarkdownOptions, render_markdown_to_html } from '@doc-utils/markdown2html';

async function main() {
  const options: MarkdownOptions = {
    // ...
    extensions: [
      my_extension
    ]
  };

  const html = await render_markdown_to_html('# This is some markdown', options);
}
```

