![Build Status](https://github.com/bylexus/grunt-md2html/workflows/grunt-md2html%20tests/badge.svg?branch=master)

# grunt-md2html

Small Grunt MultiTask based on the nodejs package [marked](https://github.com/chjj/marked) to convert Markdown files to HTML.

**Note:** Since version 0.6.0, this Grunt MultiTask needs `nodejs >= 12` and `grunt >= 1.0.0`.

* Takes input Markdown-Files
* process them using the grunt-internal template engine (lodash)
* converts them to HTML either one-by-one or many-to-one
* optionally highlight code parts using highligh.js with optional style string
* Supports embedded [ PlantUML ](https://plantuml.com/) to directly render images from PlantUML Code

## Table of Contents
- [Table of Contents](#table-of-contents)
- [Getting Started](#getting-started)
- [The "md2html" task](#the-md2html-task)
  - [Overview](#overview)
  - [Options](#options)
    - [options.layout](#optionslayout)
    - [options.basePath](#optionsbasepath)
    - [options.markedOptions](#optionsmarkedoptions)
    - [options.templateData](#optionstemplatedata)
    - [options.separator](#optionsseparator)
  - [Template variables](#template-variables)
    - [options.highlightjs](#optionshighlightjs)
    - [options.plantuml](#optionsplantuml)
  - [Usage Examples](#usage-examples)
    - [Single HTML file output](#single-html-file-output)
    - [One HTML file per md file output](#one-html-file-per-md-file-output)
    - [Options example](#options-example)
    - [Template example, including highlighjs](#template-example-including-highlighjs)
      - [grunt config](#grunt-config)
      - [Template .md file](#template-md-file)
    - [Include other .md files from within .md](#include-other-md-files-from-within-md)
      - [Example: The main file with a TOC](#example-the-main-file-with-a-toc)
      - [The separate TOC file](#the-separate-toc-file)
      - [Use '_' in your included file names to filter them from output creation](#use-_-in-your-included-file-names-to-filter-them-from-output-creation)
    - [PlantUML example](#plantuml-example)
- [Release History](#release-history)
- [License](#license)

## Getting Started
This plugin requires Grunt `^1.0.0`

If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

```shell
npm install grunt-md2html --save-dev
```

One the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

```js
grunt.loadNpmTasks('grunt-md2html');
```

## The "md2html" task

### Overview
In your project's Gruntfile, add a section named `md2html` to the data object passed into `grunt.initConfig()`.

```js
grunt.initConfig({
  md2html: {
    options: {
      // Task-specific options go here.
    },
    your_target: {
      // Target-specific file lists and/or options go here.
    },
  },
})
```

### Options

#### options.layout
Type: `String`
Default value: `null`

A path to a layout file: A Layout file defines the global surrounding layout,
e.g. an HTML header / footer. Within the Layout file you can then include the
actual processed .md-file content.

Example layout file:
```
<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="<%= basepath %>/style.css">
        <title></title>
    </head>
    <body>
        <%= document %>
    </body>
</html>
```
This layout file adds an HTML skeleton around each processed output file, replacing the template
strings `basepath` and `document ` (the processed content).


#### options.basePath
Type: `String`
Default value: `null`

If basePath is set, you can use `<%= basepath %>` in your .md / layout file, which is expanded
to a relative path from the actual output file to the given basePath. Useful to link
static resources like stylesheets in the layout file

#### options.markedOptions
Type: `Object`
Default value: `{}`

Options to be set on the `marked` package, see https://github.com/chjj/marked for details. E.g.:

```
markedOptions: {
  gfm: false
}
```

disables the GIT flavored markdown.

#### options.templateData
Type: `Object`
Default value: `{}`

Additional data which is passed to the template engine before the .md file is processed.
The data object's content is directly available as template vars / functions. See Usage Examples
for more information.


#### options.separator
Type: `String`
Default value: `'\n\n'`

A string value that is used to concatenate the .md files if used in one-outputfile mode

### Template variables

Each markdown file is first processed by the Grunt-internal Template Engine (see http://gruntjs.com/api/grunt.template). In addition to the grunt-own template variables and functions, you can use the following
variables which are replaced BEFORE processing the MD file:

* `document`: Contains the processed HTML code for a destination file. Useful for a Layout file. (For backward compatibility: use `{DOC}`).<br />
  **Note:** `document` is ONLY available in a layout file, not in a single source .md file.
* `basepath`: Points relatively to the `dest` path of the actual output, or to the given basePath in the options. (For backward compatibility: use `{BASEPATH}`)
* `destination`: The relative path to the actual destination file. (For backward compatibility: use `{DEST}`)
* `src`: The original .md source file in which the variable occurs. **NOTE:** In a layout template file (see below), this variable is an array: The grunt job can concat multiple files into one destination file.

`src` needs to be treatened differently for source files and layout files:

* in a source .md file, `src` is the path (string) to the original .md file
* in a layout template file, `src` is an array: A grunt job can concat multiple files into
  one destination, in a grunt files config like this:
```js
// Gruntfile.js
module.exports = function (grunt) {
    grunt.initConfig({
        md2html: {
            'multifiles': {
                options: {
                    layout: 'layout.html',
                },
                files: [
                    {
                        // multiple file to 1 dest:
                        src: ['multi_1.md', 'multi_2.md'],
                        dest: 'output.html'
                    }
                ]
            }
        }
    });
};
```

So make sure to use `src` appropriately:

```
// multi_1.md:
Source file: <%= src %>
```

```
// layout.html:
Source files:
<% src.forEach(function(f){ %>
- <%= f %>
<% }) %>
```


#### options.highlightjs
Type: `Object`
Default value:
```
options.highlightjs: {
    enabled: false,      // disabled by default
    style: 'monokai',    // highlightjs default theme (theme file name without .css)
    compressStyle: true, // minified version of the string based style sheet
    options: {}          // options for the highlightjs constructor
}
```

md2html includes [highlightjs](https://highlightjs.org/) if you want to highlight source code in the markdown file.
Code blocks then are enriched by highlightjs with HTML and style elements: The HTML is parsed and code blocks are sent through highlightjs before writing the final HTML.

Enable code highlighting / highlightjs tags by setting `enabled` to true.

To style the enriched code blocks, you have to include an official highlightjs CSS file:

You have two options for adding highlightjs styling / theming:

1. Include a highlightjs CSS file in your layout manually (see example [here](https://highlightjs.org/download/) )
2. Use the stringified CSS version in your template: grunt-md2html reads the original highlightjs
   style sheet as CSS string, and allows you to use it directly in your markdown file by outputting
   the template variable `highlightjs_style`:
```
<style>
  <%= highlightjs_style %>
</style>
```

An example:

```html
<!-- layout HTML file -->
<!DOCTYPE html>
<html>
    <head>
        <style>
          <%= highlightjs_style %>
        </style>
    </head>
    <body>
        <%= document %>
    </body>
</html>
```

<pre><code>
Markdown file with code snippet:
=================================
Now follows some javascript code:

```
var f = function(var1) {
    console.log(var1);
}
```
</code></pre>

#### options.plantuml
* Type: `Object`
* Default value: null
* Available configs:
```
options.plantuml: {
     // Local run:
     // Full execution command of PlantUML, without options:
    exec: 'java -jar plantuml.jar'
    // Remote run:
    // Provide the base URL for the PlantUML Render Servlet:
    renderServerUrl: "http://www.plantuml.com/plantuml"
}
```

Either **exec** or **renderServerUrl** is needed:

* If you have a local plantuml binary / JAR file, provide the full execution command in the `exec`property.
  The command is appended with PlantUML options, e.g. `java -jar plantuml.jar -tpng inputfile.html`
* If you want to use a remote PlantUML render server (see https://plantuml.com/server), provide the base URL for the render service
  with the `renderServerUrl` property. The diagram code is URL-encoded and appended to the URL, for example:
  http://www.plantuml.com/plantuml/png/UDehoIp9ILNmhLG8o4dCAmdrzL5moKnCBqhCvKhEIImkLaZBprUevb80WgJ48Yk5u9AYpBnqhbe031uI8G00`

### Usage Examples

#### Single HTML file output
In this example, all found .md files are converted to HTML and ONE html output file is generated:


```js
grunt.initConfig({
  md2html: {
      one_file: {
        options: {},
        files: [{
          src: ['my/md/files/**/*.md'],
          dest: 'out/output.html'
        }]
      }
    }
})
```

#### One HTML file per md file output
In this example, all found .md files are converted to an HTML file in the same directory.
Note that this is a base functionality of grunt's file expanding facility:


```js
grunt.initConfig({
  md2html: {
      multiple_files: {
        options: {},
        files: [{
          expand: true,
          cwd: 'base/path/to/md/files',
          src: ['**/*.md'],
          dest: 'output',
          ext: '.html'
        }]
      }
    }
});
```

#### Options example
This example just demonstrates the different options:

* layout: A layout file used for each processed output file
* basePath: The `<%= basepath %>` template variable which can be used within the docs points relatively to the basePath
* separator: concatenator string when using multiple md files which go to one output file


```js
grunt.initConfig({
  md2html: {
      multiple_files: {
        options: {
          layout: 'path/to/layout.html',
          basePath: 'path/to',
          markedOptions: {
            gfm: false,
            langPrefix: 'code-'
          }
        },
        files: [{
          expand: true,
          cwd: 'base/path/to/md/files',
          src: ['**/*.md'],
          dest: 'output',
          ext: '.html'
        }]
      }
    }
});
```


#### Template example, including highlighjs

This example demonstrates the usage of the pre-processing Template engine which can be used
to process arbitary javascript variable / functions. It also demonstrates code
highlighting using highlightjs:

##### grunt config
```js
grunt.initConfig({
  md2html: {
      multiple_files: {
        options: {
          basePath: 'path/to',
          // Provide the function `basename` and a variable `author` to the templates
          templateData: {
            basename: function(src) {
                return src.substr(src.lastIndexOf(path.sep)+1);
            },
            author: process.env.USER
          },
          highlightjs: {
            enabled: true,
            style: 'paraiso.dark',
            compressStyle: true
          },
        },
        files: [{
          expand: true,
          cwd: 'base/path/to/md/files',
          src: ['**/*.md'],
          dest: 'output',
          ext: '.html'
        }]
      }
    }
});
```

##### Template .md file
```
<style type="text/css"><%= highlightjs_style %></style>

Hello. This is an example written by <%= author %>.
It comes from the file <%= basename(src) %>, and ends in the file <%= destination %>.
Created on <%= grunt.template.today('yyyy-mm-dd HH:MM:ss') %>.

And now some highlighted code:

<pre><code>
    var fact = function(f) {
        if (f > 1) {
            return f * (fact(f-1));
        } else return 1;
    }
</code></pre>
```

#### Include other .md files from within .md

You can also include (load) other .md files within your .md files. This makes the generation of a separate TOC file, which is included in each output file, very easy:

##### Example: The main file with a TOC

Note that the file path must be relative to your Gruntfile:

```
An MD file. Include the TOC here:
<% print(grunt.file.read('gruntfile/rel/path/to/md/file.md')) %>
```

##### The separate TOC file
```
Table of contents:

* foo
* bar
```

The output html then looks as follows:

```
An MD file. Include the TOC here:
Table of contents:

* foo
* bar
```

##### Use '_' in your included file names to filter them from output creation

If you don't want to have an output file generated for each included file, you can use a file name convention:

* Start each included filename with a '_'
* Use the `filter` property in the Gruntifle's `file` definition.

Example:
```javascript
grunt.initConfig({
    md2html: {
      includeTest: {
        files: [{
          expand: true,
          cwd: 'docs',
          src: ['**/*.md'],
          // Filter away all files that begin with '_':
          filter: function(src) {
            if (path.basename(src)[0] === '_') { return false; } else { return true; }
          },
          dest: 'output',
          ext: '.html'
        }]
      }
});
```

#### PlantUML example

You can directly embed [PlantUML](https://plantuml.com/) code into your markdown/html files:

```text
<!-- document.md: -->
Markdown with embedded PlantUML
-------------------------------

Here comes my Diagram:

@startuml name-of-image
class Foo {
}
class Bar {
}
Foo <|-- Bar
@enduml

... and another:

@startuml name-of-2nd-image
Bob -> Alice : hello
@enduml
```

It is important to define the imagename `@startuml [imgname]`: This will be used as the
image filename (plus ending).

The snippets are then parsed on build time, images are generated and replaced with their
respective image markdown tags:

```text
<!-- document.md: -->
Markdown with embedded PlantUML
-------------------------------

Here comes my Diagram:

![name-of-image](name-of-image.png)

... and another:

![name-of-2nd-image](name-of-2nd-image.png)
```

The Gruntfile must enable either local or remote PlantUML rendering settings:

```js
// Gruntfile.js:
grunt.initConfig({
  md2html: {
      some_diagrams: {
        options: {
            plantuml: {
                // Local plantuml executable:
                exec: '/usr/bin/plantuml',
                // ... or remote render server:
                renderServerUrl: "http://www.plantuml.com/plantuml"
            }
        },

        files: [{
          expand: true,
          cwd: 'base/path/to/md/files',
          src: ['**/*.md'],
          dest: 'output',
          ext: '.html'
        }]
      }
    }
});
```


## Release History

* 0.1.1: Changed Markdown parser: node-markdown replaced by marked
* 0.1.1: Changed Markdown parser: node-markdown replaced by marked
* 0.1.0: Very first release, no testing yet
* 0.1.5: Fixed: '$&' in html causes the tool to crash
* 0.1.6: Updated 'marked' dependency: now uses marked 0.2.10 as dependant version
* 0.1.7: Updated 'marked' dependency: now uses marked 0.3.2
* 0.2.0: Process MD files with the grunt-internal Template engine (lodash) first.
         Keeping backwards-compatibility.
* 0.2.1: Fixing Relative Path bug: introduced in 0.2.0, the basepath was no longer relative to the options.basePath set in config in scenarios using more than one directory level.
* 0.2.2: Updated dev environment and added unit tests
* 0.3.0: highlightjs support
* 0.3.1:
  * changed dependencies to support grunt 1.x
  * updated highlightjs related documentation
* 0.4.0:
  * Adding embedded PlantUML support
  * Updating dependencies
* 0.4.1:
  * Fixing bug: if no PlantuML matches were found, but a plantuml config present, matches was null
  * minor textual changes
* 0.5.0:
  * Dropping legacy support:
    * NodeJS >= 8 is needed
    * Grunt >= 1.0.0 is needed
  * Fixing Regex `s` flag lack - replaced by `[\s\S]`
  * Fixing some nasty bugs introduced in 0.4.x
  * Updated linting and testing framework
* 0.5.1: Bugfix: basepath variable not evaluated correctly on multiple files
* 0.6.0: 
  * Updated dependencies: we use now marked 4 and highlightjs 11.
  * nodejs >= 12.0 is now required
* 0.6.1:
  * Bugfix (Issue #23): `src` variable was not available in layout templates.

## License

(c) 2013-2021 Alexander Schenkel
Licensed under the MIT License
