npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

anah

v1.1.2

Published

Handlebars to HTML compiler that accept HTML and markdown source.

Downloads

7

Readme

Anah

Handlebars to HTML compiler that accept HTML and markdown source.

Install

$ npm install anah

Features

  • Allow for markdown as sources for layouts, pages and partials. (converted with showdown)
  • Use front-matter on both HTML and markdown sources. (parsed with gray-matter)
  • Possibility to pass data in options of anah function. This can be useful to add data from database, external API, headless CMS...
  • Possibility to pass pages in options of anah function. This can be useful to add computed pages based on database, external API, headless CMS...
  • Handlebar's features also useable in markdown files.
  • Allow for json and yaml files for data.
  • Output an array of objects representing each compiled pages with their destination path, content and data.
  • Save the compiled pages in destination folder.
  • Processed page's global data accessible from template files : path from root, sub-folders depth from root, root prefix for menus.

Quick example

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

Advanced example

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

API

anah(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.

Options

pages

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!

partials

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.

helpers

Type : string

The helpers folder.

Files with .js extensions are accepted, others will be ignored.

layouts

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.

data

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

output

Type : string

The output folder.

The destination of the compiled pages.

writeOutput

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.

directData

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.

directPages

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);
Object properties
content

Type string

The content in HTML Handlebars.

data

Type object

The data for this page. Same as frontmatter for pages in path.

path

Type string

The path of the destination file, relative to the provided output option.

helpersLibraries

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

verbose

Type : boolean

Default : false

If true, show warnings and done operations.

showdownOptions

Type : object

Optional

The default options are the default options from showdown.

The showdown options can be found here.