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

@cake-hub/core

v1.0.0-alpha.16

Published

The core rendering engine for cake documentation pages.

Downloads

19

Readme

CAKE showroom core

The package @cake-hub/core helps you to export markdown documentation to usable HTML documentation. You can then make them available to other users, upload them to your website or use them in other ways. The package provides several configuration options, additional interfaces for custom markdown syntax and an extensive plugin interface.

Configuration

To keep the showroom core flexible, you can make some settings. To adjust the current configuration, you can use the function setOptions.

const core = require ("@cake-hub/core");

core.setOptions ({
    <your settings>
});

By default, the following configuration is set:

{
    mode: "production",
    projectsDirectory: null,
    outputDirectory: null,
    pathPrefix: null,
    projects: {
        configurationFileName: "cake-project.yml",
        defaultConfigurationFilePath: path.resolve(__dirname, "./templates/cake-project.yml"),
        filterFiles: null, // (filePath, projectConfiguration) => {},
    },
    logging: {
        logToConsole: true,
        logToFile: false,
        logFilePath: path.resolve(__dirname, "./logs.log"),
    },
    markdown: {
        useHighlightJs: true,
    },
}
  • mode – describes the actual environment mode (is used by the project commands)
  • projectsDirectory(required) – the directory where your project's are located
  • outputDirectory – the directory where the build documentation will be stored at (required, if you do not only use the server middleware)
  • pathPrefix – can be a string or a method (async ({ projectConfiguration, fileStructure }) => "string") returning a string to define a path prepended to every file's location
  • projects – define some basic settings for the projects
    • configurationFileName – The file name of the configuration file that should be used
    • defaultConfigurationFilePath – The path to the default project configuration file. The individual project configuration will be merged with this one.
    • filterFiles – An optional method to filter special files, that should be ignored by the build process (async (filePath, projectConfiguration) => { return true|false; })
  • logging – define some basic settings for the logging of project commands
    • logToConsole – should the project commands log to the stdout console?
    • logToFile – should the project commands log to a dedicated log-file?
    • logFilePath – the location of the log-file, if previous options was set to true
  • markdown – define some basic settings for the markdown behavior
    • useHighlightJs – a flag, if the code examples in markdown files should be rendered with highlight.js syntax

To overwrite these settings, you can use the previously named method. You can overwrite all of the default values or only the part that you want to change:

const core = require ("@cake-hub/core");

core.setOptions ({
    mode: "development",
    pathPrefix: async ({ projectConfiguration, fileStructure }) => {
        return projectConfiguration.get("brand") + "/" + projectConfiguration.get("name");
    },
    logging: {
        logToFile: true,
    },

});

If you need to access the current configuration of the core, you can simply use the method getOptions:

const core = require ("@cake-hub/core");

console.log ("current options", core.getOptions ());

Projects (configuration of projects, cake-project.yml)

The various projects whose documentation is to be rendered must all be located in the root directory of the projectsDirectory. The file cake-project.yml must be located in the respective project folder in the first hierarchy (unless otherwise configured).

The default configuration of such a file can be found at ./templates/cake-project.yml:

name: default
documentationDirectory: ./
commands: []
fileTypes: []
hiddenPrefixes: []
  • name – the name/label of this project
  • documentationDirectory – the relative path to the folder containing the documentation
  • commands – an array of commands that should be run previously to the build of the documentation (eg. commands: [{ mode: "production", name: "build", run: "sleep 2 && ls -ali" }])
    • mode – the mode when the command should be executed (see Configuration)
    • name – the name of the command to be identified
    • command – the bash command that should be executed
  • fileTypes – an array with all the extensions that should be made avaliable. if empty all files will be published (eg. fileTypes: [".md", ".jpg", ".html"])
  • hiddenPrefixes – an array containing all file/path prefixes that should be ignored (eg. hiddenPrefixes: ["_", "."])

The cake-project.yml file can be extended with custom additional values. You can later use this values inside your own plugins and markdown components.

Additionally to the fileTypes and hiddenPrefixes options you can exclude files inside your documentation folder from beeing published. This can be done with the .cakeignore file which should be located in the root folder of the project documentation. This file has a similar functionality as the .gitignore file and works with globs.

**/Ignore.*
dist
**/*.js

Commands

This library provides three different methods:

  • async initialize () – To initialize everything and run initial commands of the projects. When you change any options or plugins after this command being run, you have to re-run it.
  • async build () – This command build's the complete documentations and stores it at the configured location.
  • async server () – This method is not really a command, but a server-middleware which can be used together with the most common server frameworks.

Initialize

This command must be run before the other two commands can be used. It will prepare everything and initialize the required components. This method runs asynchronously and you should therefore wait until it's execution is finished, before calling any of the other commands.

const { initialize } = require ("@cake-hub/core");

(async () => {
    await initialize ();
})();

Build

To build a ready to use documentation you have to run the build () command. This command will go through all of your projects and render all markdown files to HTML files.

const { initialize, build } = require ("@cake-hub/core");

(async () => {
    await initialize ();
    await build ();
})();

Server

If you want to render your documentation on the fly, there is no need to build the entire projects, store them at your hard-drive and serve them to your users. You can just use the server () middleware together with your favourite server framework:

const { initialize, server } = require ("@cake-hub/core");
const express = require('express');

(async () => {
    await initialize ();

    const app = express();
    const port = 3000;

    app.use("/documentation", await server());
    app.all('*', (req, res) => {
        res.send('Error: 404!');
    });
    app.listen(port, () => {
        console.log(`Example app listening at http://localhost:${port}`)
    });
})();

Custom markdown components

Our core supports the common markdown syntax without extensions. To add custom syntax or components to the functionality, the core provides its own interface via the so-called markdown components. With this you can extend our showroom core as well as our CAKE-CMS with your own components.

To register your own components you can use the registerMarkdownComponent method as described below:

const { registerMarkdownComponent } = require ("@cake-hub/core");

registerMarkdownComponent (<your component>);

To create your own component you should extend the MarkdownComponentInterface and overwrite the provided methods with your custom implementation. The MarkdownComponentInterface already contains an example, which should help you starting.

const { registerMarkdownComponent, interfaces: { MarkdownComponentInterface } } = require ("@cake-hub/core");

class CustomMarkdownComponent extends MarkdownComponentInterface {

    // ### Just basic information about this component ###

    id() {
        return "example";
    }

    label() {
        return "My first example";
    }

    fields() {
        return [{
            name: 'source',
            label: 'Link / Href',
            widget: 'string',
        },
        {
            name: 'alt',
            label: 'Alt text',
            widget: 'string'
        }];
    }

    // ### REGEX / matching options to detect this component ###

    start(src) {
        return src.match(/^:/)?.index;
    }

    pattern() {
        return /^(?::([^:\n]+):([^:\n]*)(?:\n|$))+/;
    }

    immutableProperties () {
        return []; // properties defined in match that will not be rendered, if inline tokens are available
    }

    match(match, { tokens, lexer, options: { configuration, plugins, markdownComponents, templates }, projectConfigurations, templateEngine, fileStructure, filePath }) {
        return {
            dt: match[1] ? match[1].trim() : null,
            dd: match[2] ? match[2].trim() : null
        }
    }

    level() {
        return "inline"; // Is this a block-level or inline-level tokenizer?
        // A block-level extension will be handled before any of the block-level tokenizer methods listed above,
        // and generally consists of 'container-type' text (paragraphs, tables, blockquotes, etc.).
        // - space(string src)
        // - code(string src)
        // - fences(string src)
        // - heading(string src)
        // - hr(string src)
        // - blockquote(string src)
        // - list(string src)
        // - html(string src)
        // - def(string src)
        // - table(string src)
        // - lheading(string src)
        // - paragraph(string src)
        // - text(string src)

        // An inline-level extension will be handled inside each block-level token,
        // before any of the inline-level tokenizer methods listed above.
        // These generally consist of 'style-type' text (italics, bold, etc.).
        // - escape(string src)
        // - tag(string src)
        // - link(string src)
        // - reflink(string src, object links)
        // - emStrong(string src, string maskedSrc, string prevChar)
        // - codespan(string src)
        // - br(string src)
        // - del(string src)
        // - autolink(string src, function mangle)
        // - url(string src, function mangle)
        // - inlineText(string src, function smartypants)
    }

    // ### Generate preview / HTML ###

    htmlRenderer(data, { getAsset, fields, token, parser, options: { configuration, plugins, markdownComponents, templates }, projectConfigurations, templateEngine, fileStructure, filePath }) {
        return `<dt>${data.dt}</dt><dd>${data.dd}</dd>`;
    }

    // ### Generate source / markdown ###

    markdownRenderer (data) {
        return `: ${data.dt} : ${data.dd}\n`;
    }

    // ### Additional marked options ###

    childTokens() {
        return null;
    }

}

registerMarkdownComponent (new CustomMarkdownComponent ());

Custom plugins

Our core builds your documentation without complex configuration or custom development. But to enable custom functionality, we provide a very simple plugin interface which will help you customizating.

To register your own plugins you can use the registerMarkdownComponent method as described below:

const { registerPlugin } = require ("@cake-hub/core");

registerPlugin (<your plugin>);

To create your own plugin you should extend the PluginInterface and overwrite the provided methods with your custom implementation. The PluginInterface already contains the available methods, which should help you starting.

const { registerPlugin, interfaces: { PluginInterface } } = require ("@cake-hub/core");

class CustomPlugin extends PluginInterface {

    async afterInitialization({
        configuration,
        plugins,
        markdownComponents,
        templates,
        projectConfigurations,
        fileStructure,
        fileLists,
    }) {
        return undefined;
    }

    // Runs just before each markdown file get's rendered to HTML
    async beforeMarkdownRendering(markdownContent, {
        projectConfiguration,
        filePath,
        fileStructure,
        frontmatter,
        destinationPath,
    }) {
        return markdownContent;
    }

    // Runs just after each markdown file got rendered to HTML
    async afterMarkdownRendering(htmlContent, {
        projectConfiguration,
        filePath,
        fileStructure,
        frontmatter,
        destinationPath,
    }) {
        return htmlContent;
    }

    // Runs just after the templates has been rendered
    async afterTemplateRendering(htmlContent, {
        projectConfiguration,
        filePath,
        fileStructure,
        frontmatter,
        destinationPath,
    }) {
        return htmlContent;
    }

    // Runs just before all other files expect markdown-files get copied / streamed
    async beforeFileCopy({
        projectConfiguration,
        filePath,
        fileStructure,
    }) {
        return true; // <boolean> or <string> | <Buffer> | <TypedArray> | <DataView> | <Object> | <AsyncIterable> | <Iterable> | <Stream>
    }

    // Runs just after the build has been finished (will not execute when using the `server ()` middleware)
    async afterBuild({
        projectConfigurations,
        fileStructure,
    }) {
        return undefined;
        // Will not be run with server middleware
    }

}

registerPlugin (new CustomPlugin ());

Custom templates

Our core builds your documentation without complex configuration or custom development. But to provide you customization for the UI and how the documentation should look like in the end, we provide you a tempalte interface that you can use.

To register your own templates you can use the registerTemplate method as described below:

const { registerTemplate } = require ("@cake-hub/core");

registerTemplate (<your template>);

To create your own template you should extend the TemplateInterface and overwrite the provided methods with your custom implementation. The TemplateInterface already contains the available methods, which should help you getting started.

const { registerTemplate, interfaces: { TemplateInterface } } = require ("@cake-hub/core");

class CustomTemplate extends TemplateInterface {

    static get Options() {
        return {
            isStackable: true, // option to define, it there could be multiple templates stacked into each other, if precondition matches in multiple templates
        };
    }

    static async template(slot, { projectConfiguration, filePath, relativePath, frontmatter, markdownContent, fileStructure, configuration }) {
        return `
            <html>
                <head>
                    <title>CAKE</title>
                </head>
                <body>
                    <main>
                        ${slot}
                    </main>

                </body>
            </html>
        `;
    }

    static async precondition({ projectConfiguration, filePath, relativePath, frontmatter, markdownContent, fileStructure }) {
        // Extend this logic, to have conditional templates
        return true;
    }

}

registerTemplate (CustomTemplate);

You can register mutliple templates which can also be used in combination. The option isStackable indicates, if this template is able to stack with other templates. This means, if the option is set to true, this tempalte can be rendered inside other templates, or other templates can be rendered inside this template. Otherwise, if the option is set to false, no other template will ever be rendered inside this template.

The TemplateEngine will check for each markdown file if the precondition runs successfully (returning true) and if so, it will render the template arround the converted markdown content. If isStackable=false, the TemplateEngine will stop at the first match and return the HTML content. If isStackable=true the TemplateEngine will continue checking the other preconditions and render the template arround the markdown content and all previous templates, until one template has set option isStackable=false or all templates has been checked. The TemplateEngine will start with the last template that has been registered and finish with the first one being registered (which always is the default TemplateInterface of the core).

Interfaces

In addition to the interfaces already mentioned, the core provides further interfaces that can be used freely. These are only listed and briefly described below. To understand the exact structure, please have a look at the source files.

  • FileStructureInterface – This interface holds a list of files, that can be exported to structures mapping the file-system hierarchy.
  • FrontmatterInterface – This interface renders or parses frontmatters of markdown files and provides an api to read or change the values.
  • MarkdownComponentInterface – This interface is used to extend the default markdown render behavior.
  • PluginInterface – This interface is used to extend the default documentation building behavior.
  • TemplateInterface – This interface is used to extend or change the default UI of the build documentation.
const {
    interfaces: {
        FileStructureInterface,
        FrontmatterInterface,
        MarkdownComponentInterface,
        PluginInterface,
        TemplateInterface,
    },
} = require ("@cake-hub/core");

Modules

In addition, the core exports some helpful modules that are also used internally and provide functionality for a specific topic.

  • CommandManager – This module helps you running bash commands on your local machine and manage the logs during execution.
  • ConfigurationParser – This module helps you providing configurations with default options that can be overwritten or read.
  • FileManager – This module helps working with the file-system. Reading, Writing, Parsing files or check if it is a directory or if it even exist.
  • LoggingModule – This module helps log to the console or even into a log-file.
  • MarkdownInterpreter – This module helps parsing markdown files and convert them into useful HTML.
  • Queue – This module helps you queueing asynchronous commands into a queue and executing them in parallel.
  • TemplateEngine – This module helps managing different templates, traverse them and combining them depending on the precondition.
const {
    modules: {
        CommandManager,
        ConfigurationParser,
        FileManager,
        LoggingModule,
        MarkdownInterpreter,
        Queue,
        TemplateEngine,
    },
} = require ("@cake-hub/core");

Hint: Custom pages and content

Custom content pages that are not in markdown-format should be created just before the documentation get's build so that the files will be made available through the build process. Another option would be to create these pages afterwards and make them available at the right place afterwards.

Contact / Feature requests

You have any questions, feature requests or need furhter help? Feel free to get in touch with us!