11.4.1 • Published 27 days ago

zmarkdown v11.4.1

Weekly downloads
83
License
MIT
Repository
github
Last release
27 days ago

zmarkdown

NPM Version Test Coverage

This project is an HTTP Server API providing fast and extensible markdown parser. It is the Markdown engine powering Zeste de Savoir.

It is a small express server leveraging the remark processor and its MDAST syntax tree, rehype (for HTML processing) and textr (text transformation framework). It also provides MDAST to LaTeX compilation via rebber (and its plugins).

curl -H "Content-Type: application/json" -X POST -d '{"md":"Hello word"}' http://localhost:27272/html
#return: ["<p>Hello word</p>",{"disableToc":true,"languages":[],"depth":1},[]]

Features

  • Convert Markdown to HTML ;
  • Convert Markdown to EPUB compatible HTML ;
  • Convert Markdown to LaTeX ;
  • Convert Markdown to TEX file;
  • Convert ordered list of Markdown extracts into one of the above formats.

Installation

This is a Node.js module available through the npm registry. Install with npm:

npm install zmarkdown

Getting started

  1. Start your zmarkdown server npm run server
  2. Send a POST request to http://localhost:27272/{endpoint}

pm2 monit: provides a realtime dashboard that fits directly into your terminal, it is a simple way to monitor the resource usage of you server.

Limit the resource usage of your server

You can change the number of threads (default: 3) and the max-memory of each thread (default: 150M) in your package.json at scripts.server :

    "server": "pm2 start -f server/index.js -i 3 --max-memory-restart 150M",

Requests

All endpoints respond to HTTP POST. The request body must be JSON with a required md key. An optional opts key can be provided, the value of which depends on the endpoint.

URL

POST http://localhost:27272/{endpoint}

Body

Required Body JSON Value

NameTypeDescription
mdstringmarkdown source string or ordered list of Markdown extracts (see below)

Optional Body JSON Value

NameTypeDescription
optsJSONOptions specific to this endpoint. This object is documented in the Request section of each endpoint.

Response

All endpoints return [contents, metadata, messages] as JSON.

NameTypeDescription
contentsstringthe rendered HTML or LaTeX.
metadataobjectdepends on request options. This object is documented in the Response section of each endpoint.
messagesstring[]info/debug/errors from parsers, plugins, compilers, etc.

Only metadata is described in the Response sections below.

Endpoints

epub

Markdown to EPUB compatible HTML

URL

POST http://localhost:27272/epub

Request opts values

NameTypeDescription
opts.images_download_dirboolsee /latex
opts.local_url_to_local_pathstringsee /latex

Response metadata values

NameTypeDescription
metadata.disableTocboolWhether or not the input Markdown did not contain headings (#, ##, …). This property is named that way because we use it to disable Table of Contents generation when no headings were found.- disableToc: true means no headings- disableToc: false means at least one heading.

html

Markdown to HTML

URL

POST http://localhost:27272/html

Request opts values

NameTypeDescription
opts.disable_pingbooldefault: false, pings won't get parsed.
opts.disable_jsfiddlebooldefault: false, JSFiddle iframes are disabled.
opts.inlinebooldefault: false, Only parse inline Markdown elements (such as links and emphasis, unlike lists and fenced code blocks).
opts.statsbooldefault: false, Will compute and return statistics about markdown text.

Response metadata values

NameTypeDescription
metadata.disableTocboolWhether or not the input Markdown did not contain headings (#, ##, …). This property is named that way because we use it to disable Table of Contents generation when no headings were found.disableToc: true means no headingsdisableToc: false means at least one heading
metadata.pingstring[]undefined if opts.disable_ping: trueThe list of nicknames returned by remark-ping. Can be used to send "ping" notifications to the corresponding users.Note: this is fully customizable, remark-ping can validate potential pings by any means, including sending an HTTP request (we recommend HEAD) to a REST API to make sure this username actually exists.
metadata.languagesstring[]A list of unique languages used in GitHub Flavoured Markdown fences with a flag.
metadata.statsobjectstats about the parsed text:- signs: number of chars, spaces included.- words: number of words.

Example

Here is a quick example of the request to be made to the http://localhost:27272/html endpoint, using the software of your choice:

{
  "md": "# Hello\n\nThis is @zmarkdown, a wonderful [Markdown](https://fr.wikipedia.org/wiki/Markdown) parser. You can **embed** code in it:\n\n```js\n\nconst zmd = require('zmarkdown/modules/common')\n\n\n\nconst globalParser = common(opts, processor)\n\n```\n\n- Oh wait, this is *Mise en abyme*, isn't it?\n\n- Of course it is, you @silly.\n\n- Silly, me? Let me remind you that the main usage of this module is to launch the server directly, not using this Node.js crap:\n\n```bash\n\nnpm -g install pm2 && npm install zmarkdown\ncd ./node_modules/zmarkdown && npm run server\n\n```\n\nNow you know how it works, at least for the API endpoint, but we do support a lot more syntax, if you want.",
  "opts": {
    "stats": true
  }
}

This request will trigger the following response from the server:

[
  "<h3 id=\"hello\">Hello<a aria-hidden=\"true\" href=\"#hello\"><span class=\"icon icon-link\"></span></a></h3>\n<p>This is <a href=\"/@zmarkdown\" rel=\"nofollow\" class=\"ping ping-link\">@<span class=\"ping-username\">zmarkdown</span></a>, a wonderful <a href=\"https://fr.wikipedia.org/wiki/Markdown\">Markdown</a> parser. You can <strong>embed</strong> code in it:</p>\n<div class=\"hljs-code-div\"><div class=\"hljs-line-numbers\"><span></span><span></span><span></span><span></span><span></span></div><pre><code class=\"hljs language-js\"><span class=\"hljs-keyword\">const</span> zmd = <span class=\"hljs-built_in\">require</span>(<span class=\"hljs-string\">'zmarkdown/modules/common'</span>)\n\n\n\n<span class=\"hljs-keyword\">const</span> globalParser = common(opts, processor)\n</code></pre></div>\n<ul>\n<li>\n<p>Oh wait, this is <em>Mise en abyme</em>, isn’t it?</p>\n</li>\n<li>\n<p>Of course it is, you <a href=\"/@silly\" rel=\"nofollow\" class=\"ping ping-link\">@<span class=\"ping-username\">silly</span></a>.</p>\n</li>\n<li>\n<p>Silly, me? Let me remind you that the main usage of this module is to launch the server directly, not using this Node.js crap:</p>\n</li>\n</ul>\n<div class=\"hljs-code-div\"><div class=\"hljs-line-numbers\"><span></span><span></span></div><pre><code class=\"hljs language-bash\">npm -g install pm2 &#x26;&#x26; npm install zmarkdown\n<span class=\"hljs-built_in\">cd</span> ./node_modules/zmarkdown &#x26;&#x26; npm run server\n</code></pre></div>\n<p>Now you know how it works, at least for the API endpoint, but we do support a lot more syntax, if you want.<p>",
  {
    "ping": [
      "zmarkdown",
      "silly"
    ],
    "disableToc": false,
    "languages": [
      "js",
      "bash"
    ],
    "depth": 5,
    "stats": {
      "signs": 386,
      "words": 78
    }
  },
  []
]

LaTeX

Markdown to LaTeX

URL

POST http://localhost:27272/latex

Request opts values

NameTypeDescription
opts.disable_images_downloadboolDefault: false, does not download images.
opts.images_download_dirstringWhere to download the images to.
opts.images_download_defaultstringDefault: black.png, image used when the distant image is not found.
opts.images_download_timeoutnumberDefault: 5000 ms. HTTP request timeout for each image, in milliseconds.
opts.local_url_to_local_path-see below this table.
opts.disable_jsfiddleboolsee /html

opts.local_url_to_local_path

  • [from: string, to: string], default: <none>

    If provided, local images referenced in Markdown source (such as ![](/img/example.png)) will be copied to images_download_dir after replacing the string from with to using the following RegExp:

    '/img/example.png'.replace(new RegExp(`^${from}`), to)

Response metadata values

This endpoint only returns {} as metadata, i.e. an empty object.

TeX

Markdown to TEX file

URL

POST http://localhost:27272/latex-document

Request required opts values

These values are required.

NameTypeDescription
opts.content_typestring(required) Will be interpolated in \documentclass[${content_type}]{zmdocument}
opts.titlestring(required) Will be interpolated in \title{${title}}
opts.authors,string[](required) Will be interpolated in \author{${authors.join(', ')}}
opts.licensestring(required) E.g. CC-BY-SA will be displayed as-is, using ${license_directory}/by-sa.svg as license icon with a link to https://creativecommons.org/licenses/by-sa/4.0/legalcode
opts.license_directorystring(required) Path to the directory where CC license SVG icons are stored, see license above.
opts.smileys_directorystring(required) Path to the directory where smileys are stored.

Request opts values

NameTypeDescription
opts.disable_images_downloadboolsee /latex
opts.images_download_dirstringsee /latex
opts.images_download_defaultstringsee /latex
opts.local_url_to_local_pathstringsee /latex
opts.disable_jsfiddleboolsee /html

Response metadata values

This endpoint only returns {} as metadata, i.e. an empty object.

Manifest rendering

Since version 10.0.0, ZMarkdown supports manifest rendering, which means it is capable of processing asynchronously an ordered list of Markdown extracts, and assembling them back together. Manifest rendering works with all the four endpoints described above. Let's take an example with HTML; the following request body:

{
  "md": {"text":"# foo\n\nHello @you", "children": [{"text": "Foobar"}, {"text": "Barfoo"}]},
  "opts": {
    "stats": true
  }
}

Will lead to the following response from the server:

[
  {
    "text": "<h2 id=\"foo\">foo<a aria-hidden=\"true\" tabindex=\"-1\" href=\"#foo\"><span class=\"icon icon-link\"></span></a></h2>\n<p>Hello <a href=\"/@you\" rel=\"nofollow\" class=\"ping ping-link\">@<span class=\"ping-username\">you</span></a><p>",
    "children": [
      {
        "text": "<p>Foobar</p>"
      },
      {
        "text": "<p>Barfoo</p>"
      }
    ]
  },
  {
    "ping": [
      "you"
    ],
    "stats": {
      "signs": 24,
      "words": 5
    },
    "depth": 1,
    "disableToc": false,
    "languages": []
  },
  []
]

As you can see, the extracts are positionned in the right order, and VFiles are automatically assembled. Calling the latex-document endpoint will also concatenate the extracts and produce a complete document.

Client Architecture

Four client builds are currently available (starting from version 9.0.0), they can all be found in the client/dist folder:

  • zmarkdown-zmdast compiles Markdown to MDAST and return the result, and optionally an inspector to get a pretty output;
  • zmarkdown-zhtml compiles Markdown to HTML, using the same modules as the server, but this renderer is quite huge (1.8 MB), so it is not recommended for use in a web browser;
  • zmarkdown-zhlite is a browser-friendly version of the MD-to-HTML renderer; it has the same capabilities, except for KaTeX and highlight.js, so you'll need to provide yourself if you want to use them;
  • zmarkdown-zlatex compiles Markdown to LaTeX, using the same modules as the server.

Getting started

Simply import one of the three files mentionned above, it will expose a ZMarkdownZ*, depending on the imported file. For instance, zhlite exposes a ZMarkdownZHLITE object. This exported object have a render method, that takes the input string and a callback.

Example

ZMarkdownZHTML.render("# Hello", (err, vFile) => {
  console.log(vFile.contents);
  // will display: "<h1 id="title">Title<a aria-hidden="true" href="#title"><span class="icon icon-link"></span></a></h1>"
});

Specific MDAST renderer

The MDAST renderer is synchronous, unlike the other renderers, so it will return instead of requiring a callback. Moreover, this renderer exposes an inspect method, from unist-util-inspect.

Builds

Dev build

If you want to watch the local files while working zmarkdown, you can use npm run watch:client. Run the client by opening ./public/index.html.

Note: the current implementation (parallel-webpack) doesn't support hot-reload, you will have to manually refresh the webpage after each change.

Production build

To build for production, just run npm run release. Generated files are located in ./dist.

11.4.1

27 days ago

11.4.0

2 months ago

11.3.0

9 months ago

11.2.3

11 months ago

11.2.2

1 year ago

11.2.0

1 year ago

11.2.1

1 year ago

11.1.0

1 year ago

11.0.2

2 years ago

11.0.0

2 years ago

11.0.1

2 years ago

10.1.3

3 years ago

10.1.2

3 years ago

9.1.5

3 years ago

10.1.1

3 years ago

9.1.4

3 years ago

10.1.0

3 years ago

10.0.2

3 years ago

10.0.1

3 years ago

10.0.0

3 years ago

9.1.3

4 years ago

9.1.2

4 years ago

9.1.1

4 years ago

9.1.0

4 years ago

9.0.0

4 years ago

8.3.0

4 years ago

8.2.0

4 years ago

8.1.0

4 years ago

8.0.0

4 years ago

7.0.2

4 years ago

7.0.0

4 years ago

6.1.0

5 years ago

6.0.0

5 years ago

5.15.1

5 years ago

5.15.0

5 years ago

5.14.1

5 years ago

5.14.0

5 years ago

5.13.0

5 years ago

5.12.4

5 years ago

5.12.3

5 years ago

5.12.2

5 years ago

5.12.1

5 years ago

5.12.0

5 years ago

5.11.0

5 years ago

5.10.0

6 years ago

5.9.4

6 years ago

5.9.3

6 years ago

5.9.2

6 years ago

5.9.1

6 years ago

5.9.0

6 years ago

5.8.2

6 years ago

5.8.1

6 years ago

5.8.0

6 years ago

5.7.0

6 years ago

5.6.0

6 years ago

5.5.0

6 years ago

5.4.9

6 years ago

5.4.8

6 years ago

5.4.7

6 years ago

5.4.5

6 years ago

5.4.4

6 years ago

5.4.3

6 years ago

5.4.2

6 years ago

5.4.1

6 years ago

5.4.0

6 years ago

5.3.5

6 years ago

5.3.4

6 years ago

5.3.3

6 years ago

5.3.2

6 years ago

5.3.1

6 years ago

5.3.0

6 years ago

5.2.0

6 years ago

5.1.3

6 years ago

5.1.2

6 years ago

5.1.1

6 years ago

5.1.0

6 years ago

5.1.0-0

6 years ago

5.0.7

6 years ago

5.0.6

6 years ago

5.0.5

6 years ago

5.0.4

6 years ago

5.0.3

6 years ago

5.0.2

6 years ago

5.0.1

6 years ago

5.0.0

6 years ago

4.0.4

6 years ago

4.0.3

6 years ago

4.0.2

6 years ago

4.0.1

6 years ago

4.0.0

6 years ago

3.2.0

6 years ago

3.1.0

6 years ago

3.0.6

6 years ago

3.0.5

6 years ago

3.0.4

6 years ago

3.0.3

6 years ago

3.0.2

6 years ago

3.0.1

6 years ago

3.0.0

6 years ago

2.1.8

6 years ago

2.1.7

6 years ago

2.1.6

6 years ago

2.1.5

6 years ago

2.1.4

6 years ago

2.1.3

6 years ago

2.1.2

6 years ago

2.1.0

7 years ago

2.0.2

7 years ago

2.0.1

7 years ago

2.0.0

7 years ago

1.0.8

7 years ago

1.0.7

7 years ago

1.0.6

7 years ago

1.0.5

7 years ago

1.0.4

7 years ago

1.0.3

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago

0.0.55

7 years ago

0.0.54

7 years ago

0.0.53

7 years ago

0.0.52

7 years ago

0.0.51

7 years ago

0.0.50

7 years ago

0.0.49

7 years ago

0.0.48

7 years ago

0.0.47

7 years ago

0.0.46

7 years ago

0.0.45

7 years ago

0.0.44

7 years ago

0.0.43

7 years ago

0.0.42

7 years ago

0.0.41

7 years ago

0.0.40

7 years ago

0.0.39

7 years ago

0.0.38

7 years ago

0.0.37

7 years ago

0.0.36

7 years ago

0.0.35

7 years ago

0.0.34

7 years ago

0.0.33

7 years ago

0.0.32

7 years ago

0.0.31

7 years ago

0.0.30

7 years ago

0.0.29

7 years ago

0.0.28

7 years ago

0.0.27

7 years ago

0.0.26

7 years ago

0.0.24

7 years ago

0.0.23

7 years ago

0.0.22

7 years ago

0.0.21

7 years ago

0.0.20

7 years ago

0.0.19

7 years ago

0.0.18

7 years ago

0.0.17

7 years ago

0.0.16

7 years ago

0.0.15

7 years ago

0.0.14

7 years ago

0.0.12

7 years ago

0.0.11

7 years ago

0.0.10

7 years ago

0.0.9

7 years ago

0.0.8

7 years ago

0.0.7

7 years ago

0.0.6

7 years ago

0.0.5

7 years ago