Socket
Socket
Sign inDemoInstall

ssg-api

Package Overview
Dependencies
Maintainers
1
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ssg-api

Static Site Generation TypeScript API


Version published
Weekly downloads
3
decreased by-98.04%
Maintainers
1
Weekly downloads
 
Created
Source

ssg-api CircleCI

TypeScript API to generate output files from input files.

It can be used to generate:

  • a static website from HTML templates (but those templates can include client-side JavaScript and CSS of course).
  • (and/or) other files such as configuration files (for instance convert an .htaccess file to a netlify.toml file)

Table of contents

Setup

Install ssg-api as a project dependency:

npm install --save ssg-api

Then import the required types to implement your own SSG code:

import {Ssg, SsgContextImpl, SsgConfig} from "ssg-api"

const config: SsgConfig = {outDir: "out"}
const ssg = new Ssg(config)
        .add(firstStep)
        .add(nextStep)  // See "Concepts" for a description of steps

const context = new SsgContextImpl("fr")
try {
  const result = await ssg.start(context)
  console.log("Completed", result)
} catch (e) {
  console.error(err, context.inputFile.name, "=>", context.outputFile.name)
}

Testing

ssg-api is a provided as a native ESM package, so:

For instance, Jest will require some specifics in its jest.config.js to transform the package code (here as ts-jest config):

/** @type {import("ts-jest/dist/types").InitialOptionsTsJest} */
module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  transformIgnorePatterns: ["node_modules/(?!ssg-api)"],
  transform: {
    "^.+\\.[tj]s$": "ts-jest"
  }
}

Concepts

Steps

The Ssg execute a number of Steps, sequentially. A Step can do anything and return its own results.

Some predefined steps are provided:

Example:

import {SsgConfig, SsgContextImpl, Ssg, ContentStep, CopyStep} from "ssg-api"

const config: SsgConfig = {outDir: "out"}
const context = new SsgContextImpl("fr")

new Ssg(config)
        .add(new ContentStep(contentConfigs, outputFunc))
        .add(dir1SubdirectoriesStep)
        .add(dir2SubdirectoriesStep)
        .add(...anArrayOfSteps)
        .add(new CopyStep(copiesToDo))
        .start(context)

You can create your own steps by implementing the SsgStep interface.

ContentStep

A ContentStep is parameterized by its ContentStepConfigs. Each of these configs specifies how the ContentStep will:

  1. gather each file from its specified roots.
  2. execute its replacements on each of them, until the file doesn't change anymore.
  3. saves the modified file contents in according to its outputSpec.
Replacements

ContentStep replacements are classes implementing the ReplaceCommand interface, so you can define your own replacements.

A number predefined replace commands are also available:

and others in the repository (you'll find a number of SSI ones because RR0 used to rely on them).

  • For instance:
const contentConfigs: ContentStepConfig[] = [
  {  // A content config that converts .htaccess to netlify.toml format
    roots: [".htaccess"],
    replacements: [new HtAccessToNetlifyConfigReplaceCommand("https://rr0.org/")],
    getOutputFile(context: SsgContext): FileInfo {
      return getFileInfo(context, "netlify.toml", "utf-8")
    }
  },
  {  // A content config that replaces parts in roots
    roots: ["index.html", "404.html", "pages/**/*.html"],
    replacements: [
      new SsiIncludeReplaceCommand(),
      new TitleReplaceCommand(),
      new StringEchoVarReplaceCommand("mail"),
      new AngularExpressionReplaceCommand(),
      new SsiEchoVarReplaceCommand("copyright"),
      new SsiIfReplaceCommand(),
      new SsiSetVarReplaceCommand("title", (match: string, ...args: any[]) => `<title>${args[0]}</title>`),
      new SsiLastModifiedReplaceCommand(context.time.options),
      new AuthorReplaceCommand(),
      new HtmlTagReplaceCommand("time", new MyTimeReplacerFactory()),
      new ClassRegexReplaceCommand("people", new MyPeopleClassReplacerFactory()),
      new ClassRegexReplaceCommand("part(.?)", new MyPartXReplacerFactory()),
      new LinkReplaceCommand(),
      new AnchorReplaceCommand("https://my.base.url/")
    ],
    getOutputFile(context: SsgContext): FileInfo {
      return context.inputFile  // Under output root, I don't want to change the file path.
    }
  }
]

new Ssg(config)
        .add(new ContentStep(contentConfigs, outputFunc))
        .start(context)   // Start the generation
        .then(result => console.log("Completed", result))
        .catch(err => console.error(err, context.inputFile.name, "=>", context.outputFile.name))

FileInfo

Ssg manipulates files through a FileInfo types, which contain:

  • the name of the file (including relative path)
  • the detected (or specified) encoding of the file contents (utf8, latin1, etc.)
  • the contents of the file, as a string
  • the lastModified Date of the file
  • the detected (or specified) language of the file contents (file_fr.txt will imply french for instance).

You can:

  • get one for an existing (likely input) file using FileInfo.read(context, fileName, encoding?)
  • get or create in memory (if it doesn't exist) using FileInfo.readOrNew(context, fileName, encoding?)
  • save its (likely output) contents it in the output directory, using context.outputFile.write()
HtmlFileInfo

HTML files automatic parsing will provide additional properties:

  • title will contain the value of the <title> tag, if any
  • meta will contain values of url, copyright and author meta tags (a repeated author meta tag will result in an array of author strings)
  • links will contain values of start, contents, prev and next relationships

Context

A SsgContext is provided to Ssg methods (SsgStep.execute(content) and ReplaceCommand.execute(context)) to carry information about :

  • the current locale(s)
  • the current inputFile that has been read
  • the current outputFile that is about to be written
  • current values of variables values (through getVar()) that may have been set by current or previous replacements (through setVar()).

It also provides utility logging methods (log()/warn()/error()/debug()) and a clone() method.

You can create your own context by implementing the SsgContext interface (typically to provide custom info to custom steps).

Examples

ssg-api has been developed to generate the RR0 website, so its repository is a good place to find examples.

A good place to start is to look at RR0's build source code to see how it initializes and run its configuration, comprised of:

  • a TimeReplaceCommand to replace <time>yyyy-mm-dd hh:mm</time> tags with links to a page about that very date.
  • a PlaceReplacer to be used through a ClassDomReplaceCommand("place", new PlaceReplacerFactory(placeService)) to replace <span class="place">Paris (France)</span> tags with a clickable tag to display the map of the mentioned place.
  • a OutlineReplaceCommand to insert an outline of the current HTML page.
  • a LinkReplaceCommand to insert navigation links matching the "start", "contents", "prev" and "next" relationships of the current HTML page.
  • a CopyStep to copy images in the output dir;
  • a RR0SsgContext specializes SsgContextImpl aht adds access to locale-specific messages and time context.
  • a AnchorReplaceCommand to add trailing slash to links and a target="_blank" if the url is outside of the current website.
  • a CaseDirectoryStep and PeopleDirectoryStep to generate live indexes of UFO cases and people subdirectories.

Keywords

FAQs

Package last updated on 11 Nov 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc