
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Handlebars to HTML compiler that accept HTML and markdown source.
$ npm install anah
const anah = require("anah");
const options = {
pages: "./html/pages",
partials: "./html/partials",
helpers: "./html/helpers",
layouts: "./html/layouts",
data: "./html/data",
output: "tmp",
};
const compile = async (options) => {
await anah(options).catch((error) => console.error(error));
};
compile(options);
const options = {
pages: "./html/pages",
partials: "./html/partials",
helpers: "./html/helpers",
layouts: "./html/layouts",
data: "./html/data",
output: "tmp",
writeOutput: true, // true by default.
helpersLibraries: [
myHelperLibrary,
anOtherHelperLibrary,
{
awesomeHelper: awesomeHelperFunction,
anotherAwesomeHelper: anotherAwesomeHelperFunction,
},
],
directData: {
// computed data, external API data, headless cms data or others can be specified here
someData: {
myFirstData: "Hello",
mySecondData: "world!",
},
anotherData: 42,
},
directPages: [
// computed pages, external API pages, headless cms pages or others can be specified here
{
content: "test page!",
data: {
title: "test page",
layout: "myAwsomeLayout",
},
path: "testfolder/test",
},
{
content: "hello {{you}}",
data: {
you: "John Doe",
},
path: "people/john",
},
],
showdownOptions: {
noHeaderId: true, // showdown options can be specified here.
},
};
const compile = async (options) => {
const compiled = await anah(options).catch((error) => console.error(error));
console.log(compiled);
};
compile(options);
Returns a Promise with an Array of Objects representing the pages.
With theses template files :
layouts/default.html :
<body>
<h1>{{ title }}</h1>
{{> body }}
</body>
layouts/myAwesomeLayout.html :
<title>{{title}}</title>
{{> body }}
pages/subFolder/hello.hbs :
---
title: I'm the title provided in front-matter of hello page!
---
{{> hello}}
path to holla : {{ global.root }}{{ my_data.pages_link.holla }}
pages/holla.md :
---
title: I'm the title provided in front-matter of holla page!
---
## Holla !
partials/hello.md :
## Hello {{ who }} !
{{ myData }}
data/my_data.json :
{
"who": "John Doe",
"pages_link": {
"hello": "subFolder/hello.html",
"holla": "holla.html"
},
"persons": [
{
"name": "Nelson",
"age": 50
},
{
"name": "Jim",
"age": 25
}
],
"dogs": [
{
"name": "Rex",
"age": 3
}
]
}
data/my_data.yml :
persons:
- name: "Joe"
age: 25
- name: "Frank"
age: 15
index.js :
const adjective = "awesome";
const options = {
pages: "./html/pages",
partials: "./html/partials",
helpers: "./html/helpers",
layouts: "./html/layouts",
data: "./html/data",
output: "tmp",
directData: {
myData: `This is an ${adjective} text!`,
},
directPages: [
{
content: '<div class="awesome">{{myData}}</div>',
data: { title: "awesome page", layout: "myAwesomeLayout" },
path: "subFolder/awesome",
},
],
};
const compile = async (options) => {
const compiled = await anah(options).catch((error) => console.error(error));
console.log(compiled);
};
compile(options);
Writes in tmp/subFolder/hello.html :
<body>
<h1>I'm the title provided in front-matter of hello page!</h1>
<h2>Hello John Doe !</h2>
path to holla : ../holla.html
</body>
Writes in tmp/holla.html :
<body>
<h1>I'm the title provided in front-matter of holla page!</h1>
<h2>Holla</h2>
This is an awesome text!
</body>
Write in tmp/subFolder/awesome.html :
<title>awesome page</title>
<div class="awesome">This is an awesome text!</div>
Returned output from anah(options)
[
{
path: "./tmp/subFolder/hello.html",
content:
"<body>\r\n<h1>I'm the title provided in front-matter of hello page!</h1>\r\n<h2>Hello John Doe !</h2>\r\npath to holla : ../holla.html\r\n</body>\r\n",
data: {
// data accessible from template of hello
title: "I'm the title provided in front-matter of hello page!",
my_data: {
who: "John Doe",
pages_link: {
hello: "subFolder/hello.html",
holla: "holla.html",
},
persons: [
{ name: "Joe", age: 25 }, // yaml files override json datas.
{ name: "Frank", age: 15 }, // yaml files override json datas.
],
dogs: [{ name: "Rex", age: 3 }],
},
myData: `This is an awesome text!`,
global: { path: "subFolder/hello.html", depth: 1, root: "../" },
},
},
{
path: "./tmp/holla.html",
content:
"<body>\r\n<h1>I'm the title provided in front-matter of holla page!</h1>\r\n<h2>Holla !</h2>\r\n</body>\r\n",
data: {
// data accessible from template of holla
title: "I'm the title provided in front-matter of holla page!",
my_data: {
who: "John Doe",
pages_link: {
hello: "subFolder/hello.html",
holla: "holla.html",
},
persons: [
{ name: "Joe", age: 25 }, // yaml files override json datas.
{ name: "Frank", age: 15 }, // yaml files override json datas.
],
dogs: [{ name: "Rex", age: 3 }],
},
myData: `This is an awesome text!`,
global: { path: "holla.html", depth: 0, root: "" },
},
},
{
path: "./tmp/subFolder/awesome.html",
content:
'<title>awesome page</title>\r\n<div class="awesome">This is an awesome text!</div>\r\n',
data: {
title: "awesome page",
layout: "myAwesomeLayout",
pages_link: {
hello: "hello.html",
holla: "holla.html",
},
names: {
persons: [
{ name: "Joe", age: 25 }, // yaml files override json datas.
{ name: "Frank", age: 15 }, // yaml files override json datas.
],
dogs: [{ name: "Rex", age: 3 }],
},
myData: `This is an awesome text!`,
global: { path: "subFolder/awesome.html", depth: 1, root: "../" },
},
},
// other pages ...
];
The output path will reproduce the path found in pages folder. By default, the output will be written to the output folder provided in options. The datas are these found in the datas folder and directData merged with the frontmatter datas of the pages or these provided in directPages. Global datas are calculated by Anah and can be used in templates.
Type : string
Optional
The pages folder. The pages can be markdown or HTML.
Files with .md, .html and .hbs extension are accepted, others will be ignored.
Pages can content front-matter data. The layout used by default is the one named default in the layouts folder. The layout can be specified with layout value in front-matter :
---
layout: myLayout
---
Hello world!
Type : string
The partials folder. The pages can be markdown or HTML.
Files with .md, .html and .hbs extensions are accepted, others will be ignored.
Type : string
The helpers folder.
Files with .js extensions are accepted, others will be ignored.
Type : string
The layouts folder. The pages can be markdown or HTML.
Files with .md, .html and .hbs extension are accepted, others will be ignored.
There must at least be one layout named default in the folder.
Layout can be specified in frontmatter of pages or in data from directPages.
Type : string
The data folder. The data can be json or yaml files. If files with same names but one in json and the other in yaml, they will be mixed, but values in yaml will override the json values.
Data files can't be named global ( E.g. : global.yml or global.json).
Type : string
The output folder.
The destination of the compiled pages.
Type: boolean
Default : true
If true, allow to write the files to the destination folder in addition to return the data. Or just return the data if false.
Type: object
Optional
Here, you can provide some data. These will override the ones from data folder. This can be useful for adding some computed data, data from an external API or from an headless CMS.
The data provided in frontmatter will not be overridden.
Type object[]
Optional
Here, you can provide some pages. This can be useful for adds some computed pages based on external API, database or from an headless CMS.
It can be possible to make something like this :
const productPages = (productsFromApi) => {
const output = [];
for (const item of productsFromApi) {
output.push(
{
content: '<div>product name = {{name}}</div>',
data: {
name: item.name
},
path: `products/${item.name}`
}
)
}
return output;
};
const options = {
directPages = productPages,
// other options...
};
const compile = async (options) => {
await anah(options).catch((error) => console.error(error));
};
compile(options);
Type string
The content in HTML Handlebars.
Type object
The data for this page. Same as frontmatter for pages in path.
Type string
The path of the destination file, relative to the provided output option.
Type: object[]
Optional
Here, you can add your helpers libraries modules. They can be accessed in templates the same way than your helpers from the helpers folder.
Example :
const myLibrary = require("my-library");
const anOtherLibrary = require("an-other-library");
options.helpersLibrary = [myLibrary, anOtherLibrary];
Type : boolean
Default : false
If true, show warnings and done operations.
Type : object
Optional
The default options are the default options from showdown.
The showdown options can be found here.
FAQs
Handlebars to HTML compiler that accept HTML and markdown source.
We found that anah demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.