🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

publican.lib

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

publican.lib - npm Package Compare versions

Comparing version
0.1.1
to
0.1.2
+1
-1
package.json
{
"name": "publican.lib",
"version": "0.1.1",
"version": "0.1.2",
"description": "Standard library of functions and utilities for Publican static sites",

@@ -5,0 +5,0 @@ "type": "module",

+337
-214

@@ -1,28 +0,27 @@

# publican.lib
# Publican.lib
A standard library of functions and utilities for [Publican static sites](https://publican.dev/).
A standard library of functions and utilities for [Publican static sites](https://publican.dev/). Refer to [publican.dev/tools/publican.lib/](https://publican.dev/tools/publican.lib/) for full documentation.
## Quickstart
## Import everything
Install `publican.lib` in your Publican project:
Install Publican.lib in your Publican project:
```bash
npm i publican.lib
npm install publican.lib
```
Import it in your Publican configuration file (`publican.config.js`):
Then import it into your Publican configuration file:
```js
// publican.config.js
// Publican configuration
import { libInit } from 'publican.lib';
```
Then pass `publican` and `tacs` to the `libInit()` initialization function before calling `await publican.build();`
Pass `publican` and `tacs` to the `libInit()` initialization function before calling `await publican.build();`
```js
// set Publican defaults, e.g.
// publican.config.root = '/';
// ...set Publican defaults...
// initialize publican.dev
// initialize publican.lib
libInit(publican, tacs);

@@ -38,5 +37,5 @@

## Advanced setup
## Import individual utilities
The method above imports all library functions, but you can choose them on an individual basis, e.g.
Rather than using all functionality, you can choose to import specific functions. For example, to use all formatting and the `nav.pagination()`:

@@ -47,6 +46,7 @@ ```js

// import from Publican.lib
import * as format from 'publican.lib/format';
import { pagination } from 'publican.lib/nav';
// create global object
// create a global functions object
tacs.fn = tacs.fn || {};

@@ -62,219 +62,387 @@

## feed
## Utility functions
`feed` functions help with machine-readable feeds. All are available as `tacs.lib.feed.<fn>` functions after running `libInit()`.
The `util` library provides utility functions you can use in your Publican configuration file or elsewhere.
### `rss(str, domain, root)`
Removes invalid HTML attributes and ensures all URIs use absolute references.
### `env(name [, default])`
```html
<content:encoded><![CDATA[
${ tacs.lib.feed.rss( data.contentRendered, tacs.config.domain, tacs.root ) }
]]></content:encoded>
Fetches an environment variable, converts to a numeric value where possible, and reverts to a default when necessary:
```js
// isDev true when NODE_ENV is explicitly set to "development"
const isDev = (env('NODE_ENV', 'production') === 'development');
```
### `json(str, domain, root)`
### `apiFetch(object)`
Does the same as [`rss()`](#rssstr-domain-root) but also applies special encodings for JSON feeds.
Make an HTTP request, format the response, and cache when required. The object parameter properties:
```json
"content_html": "${ tacs.lib.feed.json( data.contentRendered, tacs.config.domain, tacs.root ) }"
```
* `uri` - required
* `method` such as `"GET"` (the default) or `"POST"`
* `headers` - optional object with name/value pairs
* `authKey` - optional request header `Authorization` token
* `contentType` - optional request header `Content-Type` (JSON by default)
* `body` - request body as a querystring, object, or array of arrays
* `timeout` - in millseconds (default of 10000 -- 10 seconds)
* `cacheDir` - cache directory location (not used by default)
* `cacheMin` - the number of minutes to cache data
Ensure special characters are fully replaced using [`replace`](#replace) settings.
The function returns an object with the following properties:
* `ok`: either `true` or `false`
* `status`: the HTTP status code (`200` for OK)
* `body`: the resulting text or JSON response (or error message)
* `error`: error code
* `cache`: the cache file name when returning cached results
### `escape(str)`
Example that caches a response for 10 minutes:
Escapes single-line HTML and XML strings.
```js
const res = await apiFetch({
uri: 'https://api.site.com/call',
authKey: 'mytoken',
cacheDir: './_cache/'
});
```html
<title>${ tacs.lib.feed.escape( data.title ) }</title>
if (res.ok) console.log(res.body);
```
## format
### `normalize(str)`
`format` functions display locale-specific values such as dates and numbers. All are available as `tacs.lib.format.<fn>` functions after running `libInit()`.
Normalizes a string to lowercase characters with hyphens in place of spaces:
```js
normalize(' Publican Library 1 ');
// returns "publican-library-1"
```
### `setLocale(locale)`
Defines the default locale when none is explicitly set in any of the following functions.
### `strHash(str)`
Hashes a string to an MD5 hex value.
```js
tacs.lib.format.setLocale( 'es-ES' );
strHash('Publican Library');
```
[`apiFetch()`](#apifetchobject) uses a hash of the HTTP URI, headers, and body as a filename when caching response data.
### `number(num [, locale])`
Returns a formatted number with appropriate thousand and fraction symbols.
### `cspScript(code [, type])`
When passed client-side JavaScript code in a string and an optional [`type` attribute](https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/script/type), `cspScript()` returns an object with the properties:
* `code`: the inline code inside a `<script>` tag, and
* `hash`: a SHA-256 hash for [Content Security Policy](https://developer.mozilla.org/docs/Web/HTTP/Guides/CSP) `script-src` settings.
```js
tacs.lib.format.number( 12345.678 ); // 12,345.678 - default US
tacs.lib.format.number( 12345.678, 'es-ES' ); // 12.345,678 - Spanish
const tacs.myScript = cspScript('alert("Hello!")');
```
You can use this in a template:
### `currency(num, currency [, locale])`
```html
<!-- Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' 'sha256-${ tacs.myScript.hash }';
">
Returns a formatted currency with appropriate thousand and fraction symbols.
<!-- add inline <script> -->
${ tacs.myScript.code }
```
> Note: Publican [minifies inline JavaScript](https://publican.dev/docs/reference/publican-options/#html-minification) 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.
```js
tacs.lib.format.currency( 12345.678, 'USD' ) // $12,345.68 - default US
tacs.lib.format.currency( 12345.678, 'USD', 'es-ES' ) // 12.345,68 $ - Spanish
const obj = [
{ name: "Craig" },
{ name: "Bob" },
{ name: "Anne" },
].sort( sortBy('name') );
// in order: Anne, Bob, Craig
```
### `numberRound(num [, locale])`
### `fileInfo(path)`
Rounds a number up depending on its size:
When passed a file path, it returns an object with the following properties:
* < 1,000: to nearest 1
* > 1,000 and < 10,000: to nearest 10
* > 10,000 and < 100,000: to nearest 100
* etc.
* `exists`: true or false
* `isFile`: true when a file
* `isDir`: true when a directory
* `modified`: the last modification timestamp
Returns an object with file information:
```js
tacs.lib.format.numberRound( 12345 ) // 12,400
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');
}
}
```
### `dateHuman(date [, locale])`
## Event hook functions
Returns a date in human-readable format:
The `hook` [event functions](https://publican.dev/docs/reference/event-functions/) append supplemental data and change some aspects of static site rendering.
### `processFileDate()`
A [processContent hook](https://publican.dev/docs/reference/event-functions/#processcontent) that sets the content [`date`](https://publican.dev/docs/reference/content-properties/#datadate) 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](https://publican.dev/docs/reference/content-properties/#dataslug), but you can remove the date with:
```js
tacs.lib.format.dateHuman('2026-09-05', 'en-US') // September 5, 2026
tacs.lib.format.dateHuman('2026-09-05', 'en-GB') // 5 September 2026
tacs.lib.format.dateHuman('2026-09-05', 'es-ES') // 5 de septiembre de 2026
// slug replacement strings - remove YYYY-MM-DD
publican.config.slugReplace.set(/\d{4}-\d{2}-\d{2}_/g, '');
```
### `dateUTC(date)`
### `contentFilename()`
Returns a date in UTC format.
A [processContent hook](https://publican.dev/docs/reference/event-functions/#processcontent) that parses a `{{ filename }}` above a code block in a markdown file. You can style the resulting HTML to show a tab or similar:
```js
tacs.lib.format.dateUTC('2026-09-05') // Sat, 5 Sep 2025 00:00:00 GMT
```html
<p class="filename language-js">
<dfn>myfile.js</dfn>
</p>
<pre class="language-js">...
```
### `dateISO(date)`
### `htmlBlocks()`
Returns a date in ISO format.
A [processContent hook](https://publican.dev/docs/reference/event-functions/#processcontent) that replaces markdown lines starting `:::` with HTML tags. For example:
```js
tacs.lib.format.dateISO('2026-09-05') // 2026-09-05
```md
::: div id="mydiv"
Some content
::: /div
```
results in the HTML:
### `dateISOfull(date)`
```html
<div id="mydiv">
Returns a full datetime in ISO format.
<p>Some content<p>
```js
tacs.lib.format.dateISOfull('2026-09-05') // 2026-09-05T00:00:00.000Z
</div>
```
### `dateYear(date)`
### `renderstartData()`
Returns a year.
A [processRenderStart hook](https://publican.dev/docs/reference/event-functions/#processrenderstart) that modifies the title and description of all tag index files to create friendlier text such as:
```js
tacs.lib.format.dateYear('2026-09-05') // 2026
* "JavaScript" posts
* List of 23 posts using the tag "JavaScript".
### `renderstartInlineScripts()`
A [processRenderStart hook](https://publican.dev/docs/reference/event-functions/#processrenderstart) that creates a global `tacs.script` JavaScript Map that defines [inline scripts using cspScript()](#cspscriptcode--type):
1. `tacs.script.get('theme')`: an inline script that appends a `data-theme` attribute to the root `<html>` element using a localStorage value
1. `tacs.script.get('speculation')`: an inline [speculation rules definition](https://developer.mozilla.org/docs/Web/API/Speculation_Rules_API)
### `prerenderInlineScripts()`
A [processPreRender hook](https://publican.dev/docs/reference/event-functions/#processprerender) that creates a `data.script` JavaScript Map for every page that defines an [inline script using cspScript()](#cspscriptcode--type):
1. `data.script.get('schema')`: an inline [schema.org](https://schema.org/) structured data block.
### `renderstartTagScore()`
A [processRenderStart hook](https://publican.dev/docs/reference/event-functions/#processrenderstart) 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](https://publican.dev/docs/reference/event-functions/#processprerender) 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:
```html
${ 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>
` : ''}
```
## hook
### `postrenderMeta()`
`hook` provides event functions to append supplemental data and can change static site rendering.
A [processPostRender hook](https://publican.dev/docs/reference/event-functions/#processpostrender) that inserts a Publican `<meta name="generator">` tag into the head of every HTML page.
### processContent hook: `processFileDate()`
## Formatting functions
Sets the `date` and `modified` date values for content when the filename matches `YYYY-MM-DD_something.md`
The `format` functions display locale-specific values such as dates and numbers.
### processContent hook: `contentFilename()`
### `setLocale(locale)`
Parses `{{ filename }}` above markdown code blocks to create code such as:
Defines the default locale when none is explicitly set in other formatting functions.
```js
tacs.lib.format.setLocale( 'es-ES' );
```
### `number(num [, locale])`
Returns a formatted number with appropriate thousand and fraction symbols.
```html
<p class="filename language-js">
<dfn><code class="language-js">format.js</code></dfn>
</p>
<p>US: ${ tacs.lib.format.number( 12345.678 ) }</p>
<p>ES: ${ tacs.lib.format.number( 12345.678, 'es-ES' ) }</p>
```
US: 12,345.678
### processContent hook: `htmlBlocks()`
ES: 12.345,678
Replaces lines starting `:::` with HTML tags, e.g.
```md
::: div id="mydiv"
### `currency(num, currency [, locale])`
Some content
Returns a formatted currency with appropriate thousand and fraction symbols.
::: /div
```html
<p>US: ${ tacs.lib.format.currency( 12345.678, 'USD' ) }</p>
<p>ES: ${ tacs.lib.format.currency( 12345.678, 'USD', 'es-ES' ) }</p>
```
results in the HTML:
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.
```html
<div id="mydiv">
<p>${ tacs.lib.format.numberRound( 12345 ) }</p>
<p>${ tacs.lib.format.numberRound( 123456 ) }</p>
```
<p>Some content<p>
12,400
</div>
124,000
### `dateHuman(date [, locale])`
Returns a date in human-readable format:
```html
<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
### processRenderStart hook: `renderstartData()`
UK: 5 September 2026
Modifies the title and description of all tag index files, e.g.
ES: 5 de septiembre de 2026
* title: "JavaScript" posts
* description: List of 23 posts using the tag "JavaScript".
### `dateUTC(date)`
### processRenderStart hook: `renderstartInlineScripts()`
Returns a date in UTC format.
Creates a `tacs.script` Map that defines [CSP scripts](#cspscriptcode--type) for theming (theme) and prerender (speculation) inline scripts.
```html
<pre>${ tacs.lib.format.dateUTC('2026-09-05T01:23:45') }</pre>
```
```txt
Sat, 05 Sep 2026 00:23:45 GMT
```
### processPreRender hook: `prerenderInlineScripts()`
Creates a `data.script` Map for every page that defines a [CSP script](#cspscriptcode--type) for structured data.
### `dateISO(date)`
Returns a date in ISO format.
### processRenderStart hook: `renderstartTagScore()`
```html
<pre>tacs.lib.format.dateISO('2026-09-05T01:23:45')</pre>
```
Creates a new `tacs.tagScore` Map object that calculates a score for each tag to help determine related articles. Lesser-used tags have a higher score.
```txt
2026-09-05
```
### processPreRender hook: `prerenderRelated()`
### `dateISOfull(date)`
Appends a `data.related` array to every page with a list of related articles in order of relevancy.
Returns a full datetime in ISO format.
```html
<pre>tacs.lib.format.dateISOfull('2026-09-05T01:23:45')</pre>
```
### postrenderMeta: `postrenderMeta()`
```txt
2026-09-05T00:23:45.000Z
```
Appends a `<meta name="generator">` tag into every HTML page.
### `dateYear(date)`
## nav
Returns a year.
`nav` functions provide navigation functions for menus and pagination. All are available as `tacs.lib.nav.<fn>` functions after running `libInit()`.
```html
<pre>tacs.lib.format.dateYear('2026-09-05T01:23:45')</pre>
```
```txt
2025
```
### `menuMain(tacs, currentPage [, allOpen, maxLevel, omit])`
Creates a hierarchical main menu using the HTML structure:
## Navigation 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:
```html

@@ -302,9 +470,9 @@ <menu>

Parameters:
The function parameters in order:
* `tacs` - the global `tacs` object - required
* `currentPage` - the current page's URL from `data.link` - required
* `allOpen` - either -1=never, 0=when child is active, or 1=always
* `maxLevel` - the maximum depth of links
* `omit` - an array of root directory names to omit
* `tacs`: the global `tacs` object (required)
* `currentPage`: the current page's URL from `data.link` (required)
* `allOpen`: either -1=never open `<details>`, 0=when child is active, or 1=always
* `maxLevel`: the maximum depth of links
* `omit`: an array of root directory names to omit

@@ -320,12 +488,12 @@ Use in a template:

### `menuDir(tacs, rootDir, currentPage [, maxLevel])`
### `menuDir()`
Creates a hierarchical menu for a specific directory using a similar structure to [`menuMain`](#menumaintacs-currentpage--allopen-maxlevel-omit), but all `<details>` have an `open` attribute set.
Creates a hierarchical menu for a specific directory using a similar structure to [`menuMain`](#menumain), but all `<details>` have an `open` attribute set.
Parameters:
* `tacs` - the global `tacs` object - required
* `rootDir` - directory name - required
* `currentPage` - the current page's URL from `data.link` - required
* `maxLevel` - the maximum depth of links
* `tacs`: the global `tacs` object (required)
* `rootDir`: the directory name (required)
* `currentPage`: the current page's URL from `data.link` (required)
* `maxLevel`: the maximum depth of links

@@ -341,3 +509,3 @@ Use in a template:

### `breadcrumb(tacs, currentPage)`
### `breadcrumb()`

@@ -357,4 +525,4 @@ Creates a breadcrumb trail to the current page using the HTML structure:

* `tacs` - the global `tacs` object - required
* `currentPage` - the current page's URL from `data.link` - required
* `tacs`: the global `tacs` object (required)
* `currentPage`: the current page's URL from `data.link` (required)

@@ -368,5 +536,5 @@ Use in a template:

### `tagList(tacs [, classPrefix, classMin, classMax])`
### `tagList()`
Generates a list of all tags ordered by a count of the articles using those tags using the HTML structure:
Generates a list of all tags ordered by ascending count of the articles using those tags. It results in the HTML structure:

@@ -388,6 +556,6 @@ ```html

* `tacs` - the global `tacs` object - required
* `classPrefix` - a `class` name to use (`taglist` by default)
* `classMin` - the minimum size counter (1 by default)
* `classMax` - the maximum size counter (5 by default)
* `tacs`: the global `tacs` object (required)
* `classPrefix`: a `class` name to use (`taglist` by default)
* `classMin`: the minimum size class (1 by default)
* `classMax`: the maximum size class (5 by default)

@@ -403,5 +571,5 @@ 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.

### `pagination(pagination)`
### `pagination()`
Generates pagination on directory and tag index pages using the HTML structure:
Generates pagination for directory and tag index pages using the HTML structure:

@@ -419,4 +587,6 @@ ```html

Use in a template by passing the page's `data.pagination` object:
Parameters:
* `pagination`: the page's `data.pagination` object (required)
```html

@@ -427,119 +597,72 @@ ${ tacs.lib.nav.pagination( data.pagination ) }

## replace
## Feed functions
`replace` provides custom string replacements that fixes common HTML issues and JSON encoding.
The `feed` functions help create machine-readable files in JSON and XML format.
### `replaceMap(root)`
### `rss(str, domain, root)`
Removes invalid HTML attributes and ensures all URIs use absolute references.
## util
`util` provides utility functions you can import, e.g.
```js
import { env, apiFetch } from 'publican.lib';
```xml
<content:encoded><![CDATA[
${ tacs.lib.feed.rss( data.contentRendered, tacs.config.domain, tacs.root ) }
]]></content:encoded>
```
### `env(name [, default])`
### `json(str, domain, root)`
Fetches an environment variable, converts to a numeric value where possible, and reverts to a default when necessary:
Does the same as [`rss()`](#rssstr-domain-root) but also applies special encodings for JSON feeds that [are replaced](#json-characters).
```js
const isDev = (env('NODE_ENV', 'production') === 'development');
```json
"content_html": "${ tacs.lib.feed.json( data.contentRendered, tacs.config.domain, tacs.root ) }"
```
### `normalize(str)`
### `escape(str)`
Normalizes a string to lowercase characters with hyphens in place of spaces:
Escapes single-line HTML and XML strings.
```js
normalize(' Publican Library 1 '); // "publican-library-1"
```html
<title>${ tacs.lib.feed.escape( data.title ) }</title>
```
### `strHash(str)`
## String replacements
Hashes a string to an MD5 hex value, as used by [`apiFetch()`](#apifetchobject) when caching HTTP requests:
The `replace` library provides a single `replaceMap()` function. It's passed the root path and returns a JavaScript Map with [string replacement](https://publican.dev/docs/setup/string-replacement/) definitions.
```js
strHash('Publican Library');
```
### Text replacements
### `cspScript(code [, type])`
* `__/` (double underscore then slash) or `−−ROOT−−` is replaced with the root path
* `−−COPYRIGHT−−` is replaced with `©<CURRENT_YEAR>`
Creates the `<script>` code with it's optional [`type` attribute](https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/script/type) and [Content Security Policy](https://developer.mozilla.org/docs/Web/HTTP/Guides/CSP) `script-src` SHA-256 hash for inline scripts. It returns an object with `code` and `hash` properties, e.g.
```js
const myScript = cspScript('alert("Hello!")');
// {
// code: "<script>alert("Hello")</script>",
// hash: "abc..."
// }
```
### Style replacements
All elements with a `style` attribute setting the text alignment have `class="center"` or `class="right"` assigned accordingly.
### `sortBy(prop)`
A function to sort an array using property values, e.g.
### Table scrolling
```js
const obj = [
{ name: "Craig" },
{ name: "Bob" },
{ name: "Anne" },
].sort( sortBy('name') );
// now in Anne, Bob, Craig order
```
All `<table>` elements get a `<div class="tablescroll">` container to help with scrolling on smaller devices (set `overflow-inline: auto;` in CSS).
### `apiFetch(object)`
### Unnecessary paragraphs
Make an HTTP request with optional caching. The object parameters:
Unnecessary `<p>` tags are removed from around `<img>`, `<svg>`, and `<iframe>` elements.
* `uri` - required
* `method` such as `"GET"` (the default) or `"POST"`
* `headers` - optional object with name/value pairs
* `authKey` - optional request header Authorization token
* `contentType` - optional request header Content-Type (JSON by default)
* `body` - request body as a querystring, object, or array of arrays
* `timeout` - in millseconds (default of 10000)
* `cacheDir` - the location of the cache directory (not used by default)
* `cacheMin` - the number of minutes to cache request data
The function returns an object with the following properties:
### Image handling
* `ok`: either `true` or `false`
* `status`: the HTTP status code (200 for OK)
* `body`: the resulting text or JSON response (or error message)
* `error`: error code
* `cache`: the cache file name when returning cached results
When not explicitly set on `<img>` tags:
Example:
* `alt` attributes are added, and
* `loading="lazy"` is set
```js
const res = await apiFetch({
uri: 'https://api.site.com/call',
authKey: 'mytoken'
});
if (res.ok) console.log(res.body);
```
### JSON characters
### `fileInfo(path)`
Returns an object with file information:
```js
const info = fileInfo('./some-file.txt');
// {
// exists: true,
// isFile: true,
// isDir: false,
// modified: 12345678 (timestamp)
// }
```
Special characters for [JSON feeds](#jsonstr-domain-root) are replaced.