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

mhcms

v0.5.7

Published

Minimal Headless Content Management System

Downloads

4

Readme

MHCMS: Minimal Headless CMS

Overview

A very simple headless CMS that uses folder and markdown files instead of a database. That means you can now use your favorite code editor instead of some irritating web GUI. It supports the local file system and S3 out of the box. If you need more, you can implement your own IMhcmsFileAccess class.

The publication date and short titles are stored inside file names. Other metadata and the body of articles are stored inside the files themselves. It is based on an indexing system, that is updated when needed. Still, it will be very slow compared to a classic DB-based approach: think twice before using it.

Basic usage is illustrated in the sample code at sample/read-blog.ts.

Specifications

Blog posts are markdown files with a header. The file name must respect the naming convention YYYYMMDD_a-short-title.md, where:

  • YYYYMMDD is day at which the article will be published. If the date is in the future, it will only be considered hidden unless this date
  • a-short-title is the short title of the article, in kebab case. It is converted into a sentence by system, e.g. “A short title“.

The header consists of keys and values separated by a colon, one per line. A header ends with a line that contains at least three hyphens. Spaces around keys and values are ignored. Keys can be specified in any case, but are converted to camel case.

These keys must be present in every blog post: title, subTitle, tags, authors. Tags and authors are comma-separated lists of strings. Title and subTitle are strings. Extra keys can be present, but you will need to provide a custom deserializer to parse the values.

Below is an article with the bare minimum

title: This is a test post
sub-title: Not much to say
tags:
authors:
---

This is the content of the article, in *markdown* syntax.

The File Tree

Articles should be organized in one level of sub-folder, inside the root folder. For example:

+ ./blog
  + drafts/
    20230820_Some-blog-post.md
  + published/
    00011225_Who-is-born.md

The example above uses sub-folder drafts and published, but it can be anything. We call these sub-folders "collections".

At the root (e.g. the ./blog folder in the example above), MHCMS will create an index file with the name index.yaml. It contains the list of paths together with their header data. It is human-readable, but it is usually a bad idea to edit it by hand. If you delete this file, you will need to re-generate it for the system to work.

Client Sample Code

For a simple blog with drafts and published folders, you can list posts with:

import { MhcmsClient, LocalFileAccess } from 'mhcms';

const CMS_ROOT = "/some/folder"

const _mhcms = await MhcmsClient.simpleBlog(new LocalFileAccess(CMS_ROOT)).folder("blog");
if (_mhcms.isNg()) {
  console.log("Unable to open blog: " + _mhcms.pretty());
  return;
}
const mhcms = _mhcms.value;

const publishedArticles = mhcms.articles("published");

for (let article of publishedArticles) {
  console.log(article.title);
}

Markdown Extension

If you wish, you can parse the paragraphs within a section. Paragraphs are blocks of text separated by an empty line. In this case, MHCMS does some extra parsing to better structure your data.

Normal text paragraphs are stored with te boring structure below:

interface IMhcmsTextArticleParagraph {
    readonly type: "text"
    readonly content: string;
}

Quote Extensions

It is possible to specify the author of a quote by prepending at least one hyphen to the last line of the quote

> I ate cereals this morning
> --- Sir Quaker

Quotation blocks are stored with structure:

interface IMhcmsQuoteArticleParagraph {
    readonly type: "quote"
    readonly content: string;
    readonly author?: string;
}

Code Block Extension

Code blocks are represented with the interface below:

interface IMhcmsCodeBlockArticleParagraph {
    readonly type: "code-block"
    readonly language?: string;
    readonly content: string;
    readonly options?: Record<string, string | boolean | number>;
}

It is possible to specify the language directly after the three backquotes. You can also use further structure with curly-brace syntax {language key=value bool-key !bool-key @system-key}. The value supports single and double quotes as well.

The supported system keys are:

  • @parse: MHCMS parses the code block into an object, and stores in member content instead of a string. Only JSON and YAML are supported for now

TODO

  • special [] syntaxes
evaluateTextParapgraph(
  commands: Record<str, (...args: string[])>,
  imgBase: str | { prefix: replace } | (url: string) => string,
  urlBase: str | { prefix: replace } | (url: string) => string,
)

[html-tag.class content], e.g. [kbd A] [span.red yay] [!cmd arg1, arg2] e.g. [!year]

  • specify a callback for image or links (not sure how that would work)
  • @array to convert into html arrays