@sphido/core

Sphido core package contains two most important function getPages() and allPages(). The getPages() function scans directories for all *.md and *.html files. Second function allPages() is generator that allow to iterate over all pages.

const pages = await getPages({path: 'content'}, /* ...exteners */);

Returned structure is very simple and looks like follow:

[
  {
    "name": "Main page",
    "path": "content/Main page.md"
  },
  {
    "name": "Directory",
    "children": [
      {
        "name": "Subpage one",
        "path": "content/Directory/Subpage one.md"
      },
      {
        "name": "Subpage two",
        "path": "content/Directory/Subpage two.md"
      }
    ]
  }
]

Then iterate over pages like follow:

for (const page of allPages(pages)) {
  console.log(page);
}

Extending page object

Every single page object inside structure can be modified with extender. Extenders are set as additional parameters of the getPages() function. There are two types of extenders:

Callback extenders

Callback extender is a function that is called during recursion over each page with three parameters passed to the function page, path and dirent.

const callbackExtender = (page, path, dirent) => {
  // do anything with page object
}

const pages = await getPages({path: 'content'}, callbackExtender);

Object extenders

This extender is just a simple JavaScript object that is combined with the page object using the Object.assign() function.

const objectExtender = {
  author: 'Roman Ožana'
}

const pages = await getPages({path: 'content'}, objectExtender);

There is no limit to the number of extenders, you can combine as many as you want. Let's have the following code:

const extenders = [

	// callback extenders will be called during iteration ony by one

	(page) => {
		// add property
		page.title = `${page.name} | my best website`;

		// or function
		page.getDate = () => new Date();

		// or something else 
		page.counter = 1;
	},

	// callback extenders are called in the series
  
	(page) => {
		page.counter++;
	},

	// object extender will be merged with page object
  
	{
		"author": "Roman Ožana",
		"getLink": function () {
			return this.path.replace('content', 'public');
		}
	}
];

const pages = getPages({path: 'content'}, ...extenders);

then you get this structure:

[
  {
    "name": "Main page",
    "path": "content/Main page.md",
    "title": "Main page | my best website",
    "counter": 2,
    "author": "Roman Ožana",
    "getDate": "[Function: getDate]",
    "getLink": "[Function: getLink]"
  }
]

Installation

yarn add @sphido/core

Example

Following example read all *.md files in content directory and process them with marked to HTML files

#!/usr/bin/env node

import {dirname, relative, join} from 'node:path';
import {getPages, allPages, readFile, writeFile} from '@sphido/core';
import slugify from '@sindresorhus/slugify';
import {marked} from 'marked';

const pages = await getPages({path: 'content'}, // ... extenders
  (page) => {
    page.slug = slugify(page.name) + '.html';
    page.dir = dirname(page.path);
  });

for (const page of allPages(pages)) {
  page.output = join('public', relative('content', page.dir), page.slug);
  page.content = marked(await readFile(page.path));

  await writeFile(page.output, `<!DOCTYPE html>
		<html lang="en" dir="ltr">
		<head>
			<meta charset="UTF-8">
			<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
			<title>${page.name} | Sphido Example</title>
		</head>
		<body class="prose mx-auto my-6">${page.content}</body>
		<!-- Generated by Sphido from ${page.path} -->
		</html>
  `);
}

Source codes

@sphido/core