publican.lib
v0.1.2
Published
Standard library of functions and utilities for Publican static sites
Maintainers
Readme
Publican.lib
A standard library of functions and utilities for Publican static sites. Refer to publican.dev/tools/publican.lib/ for full documentation.
Import everything
Install Publican.lib in your Publican project:
npm install publican.libThen import it into your Publican configuration file:
// Publican configuration
import { libInit } from 'publican.lib';Pass publican and tacs to the libInit() initialization function before calling await publican.build();
// ...set Publican defaults...
// initialize publican.lib
libInit(publican, tacs);
// optionally set the default language
tacs.lib.format.setLocale( 'en-US' );
// build
await publican.build();Import individual utilities
Rather than using all functionality, you can choose to import specific functions. For example, to use all formatting and the nav.pagination():
// Publican configuration
import { Publican, tacs } from 'publican';
// import from Publican.lib
import * as format from 'publican.lib/format';
import { pagination } from 'publican.lib/nav';
// create a global functions object
tacs.fn = tacs.fn || {};
// use all tacs.fn.format functions in templates
tacs.fn.format = format;
// use tacs.fn.nav.pagination() function in templates
tacs.fn.nav = { pagination };Utility functions
The util library provides utility functions you can use in your Publican configuration file or elsewhere.
env(name [, default])
Fetches an environment variable, converts to a numeric value where possible, and reverts to a default when necessary:
// isDev true when NODE_ENV is explicitly set to "development"
const isDev = (env('NODE_ENV', 'production') === 'development');apiFetch(object)
Make an HTTP request, format the response, and cache when required. The object parameter properties:
uri- requiredmethodsuch as"GET"(the default) or"POST"headers- optional object with name/value pairsauthKey- optional request headerAuthorizationtokencontentType- optional request headerContent-Type(JSON by default)body- request body as a querystring, object, or array of arraystimeout- in millseconds (default of 10000 -- 10 seconds)cacheDir- cache directory location (not used by default)cacheMin- the number of minutes to cache data
The function returns an object with the following properties:
ok: eithertrueorfalsestatus: the HTTP status code (200for OK)body: the resulting text or JSON response (or error message)error: error codecache: the cache file name when returning cached results
Example that caches a response for 10 minutes:
const res = await apiFetch({
uri: 'https://api.site.com/call',
authKey: 'mytoken',
cacheDir: './_cache/'
});
if (res.ok) console.log(res.body);normalize(str)
Normalizes a string to lowercase characters with hyphens in place of spaces:
normalize(' Publican Library 1 ');
// returns "publican-library-1"strHash(str)
Hashes a string to an MD5 hex value.
strHash('Publican Library');apiFetch() uses a hash of the HTTP URI, headers, and body as a filename when caching response data.
cspScript(code [, type])
When passed client-side JavaScript code in a string and an optional type attribute, cspScript() returns an object with the properties:
code: the inline code inside a<script>tag, andhash: a SHA-256 hash for Content Security Policyscript-srcsettings.
const tacs.myScript = cspScript('alert("Hello!")');You can use this in a template:
<!-- Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'sha256-${ tacs.myScript.hash }';
">
<!-- add inline <script> -->
${ tacs.myScript.code }Note: Publican minifies inline JavaScript by default. Always pass a minified script to
cspScript()to ensure it's not minified and the CSP hash remains the same.
sortBy(prop)
A function to sort an array using property values, e.g.
const obj = [
{ name: "Craig" },
{ name: "Bob" },
{ name: "Anne" },
].sort( sortBy('name') );
// in order: Anne, Bob, CraigfileInfo(path)
When passed a file path, it returns an object with the following properties:
exists: true or falseisFile: true when a fileisDir: true when a directorymodified: the last modification timestamp
Returns an object with file information:
const
file = './somefile.txt',
info = fileInfo(file);
if (info.exists) {
console.log(file);
if (info.isFile) {
console.log('is a file');
}
else if (info.isDir) {
console.log('is a directory');
}
}Event hook functions
The hook event functions append supplemental data and change some aspects of static site rendering.
processFileDate()
A processContent hook that sets the content date and modified properties for any content file using a file name pattern YYYY-MM-DD_something.md.
It does not alter the rendered file slug, but you can remove the date with:
// slug replacement strings - remove YYYY-MM-DD
publican.config.slugReplace.set(/\d{4}-\d{2}-\d{2}_/g, '');contentFilename()
A processContent hook that parses a {{ filename }} above a code block in a markdown file. You can style the resulting HTML to show a tab or similar:
<p class="filename language-js">
<dfn>myfile.js</dfn>
</p>
<pre class="language-js">...htmlBlocks()
A processContent hook that replaces markdown lines starting ::: with HTML tags. For example:
::: div id="mydiv"
Some content
::: /divresults in the HTML:
<div id="mydiv">
<p>Some content<p>
</div>renderstartData()
A processRenderStart hook that modifies the title and description of all tag index files to create friendlier text such as:
- "JavaScript" posts
- List of 23 posts using the tag "JavaScript".
renderstartInlineScripts()
A processRenderStart hook that creates a global tacs.script JavaScript Map that defines inline scripts using cspScript():
tacs.script.get('theme'): an inline script that appends adata-themeattribute to the root<html>element using a localStorage valuetacs.script.get('speculation'): an inline speculation rules definition
prerenderInlineScripts()
A processPreRender hook that creates a data.script JavaScript Map for every page that defines an inline script using cspScript():
data.script.get('schema'): an inline schema.org structured data block.
renderstartTagScore()
A processRenderStart hook that creates a global tacs.tagScore JavaScript Map object that calculates a score for each tag (lesser-used tags have a higher score). This helps determine related articles.
prerenderRelated()
A processPreRender hook that appends a data.related array to every page with a list of related articles in order of relevancy. To output the three most-relevant related articles:
${ data?.related?.length ? `
<aside>
<h2>Related posts</h2>
<nav>
${ data.related
.slice(0,3)
.map(p => `<p><a href="{ p.link }">${ p.title }</a></p>`)
.join('') }
</nav>
</aside>
` : ''}postrenderMeta()
A processPostRender hook that inserts a Publican <meta name="generator"> tag into the head of every HTML page.
Formatting functions
The format functions display locale-specific values such as dates and numbers.
setLocale(locale)
Defines the default locale when none is explicitly set in other formatting functions.
tacs.lib.format.setLocale( 'es-ES' );number(num [, locale])
Returns a formatted number with appropriate thousand and fraction symbols.
<p>US: ${ tacs.lib.format.number( 12345.678 ) }</p>
<p>ES: ${ tacs.lib.format.number( 12345.678, 'es-ES' ) }</p>US: 12,345.678
ES: 12.345,678
currency(num, currency [, locale])
Returns a formatted currency with appropriate thousand and fraction symbols.
<p>US: ${ tacs.lib.format.currency( 12345.678, 'USD' ) }</p>
<p>ES: ${ tacs.lib.format.currency( 12345.678, 'USD', 'es-ES' ) }</p>US: $12,345.68
ES: 12.345,68 $
numberRound(num [, locale])
Rounds a number up depending on its size:
- < 1,000: to nearest 1
- > 1,000 and < 10,000: to nearest 10
- > 10,000 and < 100,000: to nearest 100
- etc.
<p>${ tacs.lib.format.numberRound( 12345 ) }</p>
<p>${ tacs.lib.format.numberRound( 123456 ) }</p>12,400
124,000
dateHuman(date [, locale])
Returns a date in human-readable format:
<p>US: ${ tacs.lib.format.dateHuman('2026-09-05', 'en-US') }</p>
<p>UK: ${ tacs.lib.format.dateHuman('2026-09-05', 'en-GB') }</p>
<p>ES: ${ tacs.lib.format.dateHuman('2026-09-05', 'es-ES') }</p>US: September 5, 2026
UK: 5 September 2026
ES: 5 de septiembre de 2026
dateUTC(date)
Returns a date in UTC format.
<pre>${ tacs.lib.format.dateUTC('2026-09-05T01:23:45') }</pre>Sat, 05 Sep 2026 00:23:45 GMTdateISO(date)
Returns a date in ISO format.
<pre>tacs.lib.format.dateISO('2026-09-05T01:23:45')</pre>2026-09-05dateISOfull(date)
Returns a full datetime in ISO format.
<pre>tacs.lib.format.dateISOfull('2026-09-05T01:23:45')</pre>2026-09-05T00:23:45.000ZdateYear(date)
Returns a year.
<pre>tacs.lib.format.dateYear('2026-09-05T01:23:45')</pre>2025Navigation functions
The nav functions provide HTML menus and pagination.
menuMain()
Creates a hierarchical main menu using the HTML <menu> structure with <details> and <summary> elements:
<menu>
<li>
<details>
<summary><a href="/one/">Level One</a></summary>
<menu>
<li><strong>Active page</strong></li>
<li>
<details>
<summary><a href="/two/">Level Two</a></summary>
<menu>
<li><a href="/sub2-1/">Sub-menu 2-1</a></li>
<li><a href="/sub2-2/">Sub-menu 2-2</a></li>
</menu>
</details>
</li>
</menu>
<details>
</li>
</menu>The function parameters in order:
tacs: the globaltacsobject (required)currentPage: the current page's URL fromdata.link(required)allOpen: either -1=never open<details>, 0=when child is active, or 1=alwaysmaxLevel: the maximum depth of linksomit: an array of root directory names to omit
Use in a template:
<nav id="main">
${ tacs.lib.nav.menuMain( tacs, data.link ) }
</nav>menuDir()
Creates a hierarchical menu for a specific directory using a similar structure to menuMain, but all <details> have an open attribute set.
Parameters:
tacs: the globaltacsobject (required)rootDir: the directory name (required)currentPage: the current page's URL fromdata.link(required)maxLevel: the maximum depth of links
Use in a template:
<nav id="documentation">
${ tacs.lib.nav.menuDir( tacs, 'doc', data.link ) }
</nav>breadcrumb()
Creates a breadcrumb trail to the current page using the HTML structure:
<nav class="breadcrumb">
<ol>
<li><a href="/grandparent/">Grand parent</a></li>
<li><a href="/parent/">Parent</a></li>
</ol>
</nav>Parameters:
tacs: the globaltacsobject (required)currentPage: the current page's URL fromdata.link(required)
Use in a template:
${ tacs.lib.nav.breadcrumb( tacs, data.link ) }tagList()
Generates a list of all tags ordered by ascending count of the articles using those tags. It results in the HTML structure:
<nav class="taglist">
<ul>
<li class="taglist5"><a href="/tag/one/">one <sup>19</sup></a></li>
<li class="taglist4"><a href="/tag/two/">two <sup>17</sup></a></li>
<li class="taglist3"><a href="/tag/three/">three <sup>15</sup></a></li>
<li class="taglist2"><a href="/tag/four/">four <sup>13</sup></a></li>
<li class="taglist2"><a href="/tag/five/">five <sup>13</sup></a></li>
<li class="taglist1"><a href="/tag/six/">six <sup>10</sup></a></li>
</ul>
</nav>Parameters:
tacs: the globaltacsobject (required)classPrefix: aclassname to use (taglistby default)classMin: the minimum size class (1 by default)classMax: the maximum size class (5 by default)
The most-used tag has a class of taglist5. The least-used tag has a class of taglist1. All other tags have a value between.
Use in a template:
${ tacs.lib.nav.tagList(tacs) }pagination()
Generates pagination for directory and tag index pages using the HTML structure:
<nav class="pagination">
<ul>
<li class="back"><span>◄</span></li>
<li class="current"><strong>1</strong></li>
<li><a href="/tag/one/1/">2</a></li>
<li class="next"><a href="/tag/one/1/" title="next index page">►</a></li>
</ul>
</nav>Parameters:
pagination: the page'sdata.paginationobject (required)
${ tacs.lib.nav.pagination( data.pagination ) }Feed functions
The feed functions help create machine-readable files in JSON and XML format.
rss(str, domain, root)
Removes invalid HTML attributes and ensures all URIs use absolute references.
<content:encoded><![CDATA[
${ tacs.lib.feed.rss( data.contentRendered, tacs.config.domain, tacs.root ) }
]]></content:encoded>json(str, domain, root)
Does the same as rss() but also applies special encodings for JSON feeds that are replaced.
"content_html": "${ tacs.lib.feed.json( data.contentRendered, tacs.config.domain, tacs.root ) }"escape(str)
Escapes single-line HTML and XML strings.
<title>${ tacs.lib.feed.escape( data.title ) }</title>String replacements
The replace library provides a single replaceMap() function. It's passed the root path and returns a JavaScript Map with string replacement definitions.
Text replacements
__/(double underscore then slash) or−−ROOT−−is replaced with the root path−−COPYRIGHT−−is replaced with©<CURRENT_YEAR>
Style replacements
All elements with a style attribute setting the text alignment have class="center" or class="right" assigned accordingly.
Table scrolling
All <table> elements get a <div class="tablescroll"> container to help with scrolling on smaller devices (set overflow-inline: auto; in CSS).
Unnecessary paragraphs
Unnecessary <p> tags are removed from around <img>, <svg>, and <iframe> elements.
Image handling
When not explicitly set on <img> tags:
altattributes are added, andloading="lazy"is set
JSON characters
Special characters for JSON feeds are replaced.
