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

@uttori/wiki

v6.0.4

Published

Uttori Wiki is a wiki functionality module for Uttori.

Downloads

34

Readme

view on npm npm module downloads Build Status Coverage Status

Uttori Wiki

UttoriWiki is a fast, simple, wiki / knowledge base built around Express.js using the Uttori set of components allowing single chunks of functionality be changed or swapped out to fit specific needs.

Why yet another knowledge management / note taking app? I wanted to have something that functioned as a Wiki or Blog or similar small app that I could reuse components for and keep extensible.

Because of that, UttoriWiki is plugin based. Search and Storage engines are fully configurable. The format of the data is also up to you: Markdown, Wikitext, Creole, AsciiDoc, Textile, reStructuredText, BBCode, Pendown, etc.

Nothing is prescribed. Don't want to write in Markdown? You don't need to! Don't want to store files on disk? Choose a database storage engine! Already running a bunch of external dependencies and want to plug into those? You can most likely do it!

Rendering happens in a pipeline making it easy to render to Markdown, then filter words out and replace text with emojis.

If you want to test it out, check out the demo repo to get up and going in a minutes.

Configuration

Please see src/config.js or the config doc for all options. Below is an example configuration using some plugins:

import { Plugin: StorageProvider } from '@uttori/storage-provider-json-file';
import { Plugin: SearchProvider } from '@uttori/search-provider-lunr';

import AnalyticsPlugin from '@uttori/plugin-analytics-json-file';
import MarkdownItRenderer from '@uttori/plugin-renderer-markdown-it';
import ReplacerRenderer from '@uttori/plugin-renderer-replacer';
import MulterUpload from '@uttori/plugin-upload-multer';
import SitemapGenerator from '@uttori/plugin-generator-sitemap';
import { AddQueryOutputToViewModel } from '@uttori/wiki';

const config = {
  homePage: 'home-page',
  ignoreSlugs: ['home-page'],
  excerptLength: 400,
  publicUrl: 'http://127.0.0.1:8000/wiki',
  themePath: path.join(__dirname, 'theme'),
  publicPath: path.join(__dirname, 'public'),
  useDeleteKey: false,
  deleteKey: process.env.DELETE_KEY || '',
  useEditKey: false,
  editKey: process.env.EDIT_KEY || '',
  publicHistory: true,
  allowedDocumentKeys: [],

  // Plugins
  plugins: [
    StorageProvider,
    SearchProvider,
    AnalyticsPlugin,
    MarkdownItRenderer,
    ReplacerRenderer,
    MulterUpload,
    SitemapGenerator,
  ],

  // Use the JSON to Disk Storage Provider
  [StorageProvider.configKey]: {
    // Path in which to store content (markdown files, etc.)
    contentDirectory: `${__dirname}/content`,

    // Path in which to store content history (markdown files, etc.)
    historyDirectory: `${__dirname}/content/history`,

    // File Extension
    extension: 'json',
  },

  // Use the Lunr Search Provider
  [SearchProvider.configKey]: {
    // Optional Lunr locale
    lunr_locales: [],

    // Ignore Slugs
    ignoreSlugs: ['home-page'],
  },

  // Plugin: Analytics with JSON Files
  [AnalyticsPlugin.configKey]: {
    events: {
      getPopularDocuments: ['popular-documents'],
      updateDocument: ['document-save', 'document-delete'],
      validateConfig: ['validate-config'],
    },

    // Directory files will be uploaded to.
    directory: `${__dirname}/data`,

    // Name of the JSON file.
    name: 'visits',

    // File extension to use for the JSON file.
    extension: 'json',
  },

  // Plugin: Markdown rendering with MarkdownIt
  [MarkdownItRenderer.configKey]: {
    events: {
      renderContent: ['render-content'],
      renderCollection: ['render-search-results'],
      validateConfig: ['validate-config'],
    },


    // Uttori Specific Configuration
    uttori: {
      // Prefix for relative URLs, useful when the Express app is not at root.
      baseUrl: '',

      // Safe List, if a domain is not in this list, it is set to 'external nofollow noreferrer'.
      allowedExternalDomains: [
        'my-site.org',
      ],

      // Open external domains in a new window.
      openNewWindow: true,

      // Table of Contents
      toc: {
        // The opening DOM tag for the TOC container.
        openingTag: '<nav class="table-of-contents">',

        // The closing DOM tag for the TOC container.
        closingTag: '</nav>',

        // Slugify options for convering content to anchor links.
        slugify: {
          lower: true,
        },
      },
    },
  },

  // Plugin: Replace text
  [ReplacerRenderer.configKey]: {
    events: {
      renderContent: ['render-content'],
      renderCollection: ['render-search-results'],
      validateConfig: ['validate-config'],
    },

    // Rules for text replace
    rules: [
      {
        test: /bunny|rabbit/gm,
        output: '🐰',
      },
    ],
  },

  // Plugin: Multer Upload
  [MulterUpload.configKey]: {
    events: {
      bindRoutes: ['bind-routes'],
      validateConfig: ['validate-config'],
    },

    // Directory files will be uploaded to
    directory: `${__dirname}/uploads`,

    // URL to POST files to
    route: '/upload',

    // URL to GET uploads from
    publicRoute: '/uploads',
  },

  // Plugin: Sitemap Generator
  [SitemapGenerator.configKey]: {
    events: {
      callback: ['document-save', 'document-delete'],
      validateConfig: ['validate-config'],
    },

    // Sitemap URL (ie https://wiki.domain.tld)
    base_url: 'https://wiki.domain.tld',

    // Location where the XML sitemap will be written to.
    directory: `${__dirname}/themes/default/public`,

    urls: [
      {
        url: '/',
        lastmod: new Date().toISOString(),
        priority: '1.00',
      },
      {
        url: '/tags',
        lastmod: new Date().toISOString(),
        priority: '0.90',
      },
      {
        url: '/new',
        lastmod: new Date().toISOString(),
        priority: '0.70',
      },
    ],
  },

  // Plugin: View Model Related Documents
  [AddQueryOutputToViewModel.configKey]: {
    events: {
      callback: [
        'view-model-home',
        'view-model-edit',
        'view-model-new',
        'view-model-search',
        'view-model-tag',
        'view-model-tag-index',
        'view-model-detail',
      ],
    },
    queries: {
      'view-model-home' : [
        {
          key: 'tags',
          query: `SELECT tags FROM documents WHERE slug NOT_IN ("${ignoreSlugs.join('", "')}") ORDER BY id ASC LIMIT -1`,
          format: (tags) => [...new Set(tags.flatMap((t) => t.tags))].filter(Boolean).sort((a, b) => a.localeCompare(b)),
          fallback: [],
        },
        {
          key: 'documents',
          query: `SELECT * FROM documents WHERE slug NOT_IN ("${ignoreSlugs.join('", "')}") ORDER BY id ASC LIMIT -1`,
          fallback: [],
        },
        {
          key: 'popularDocuments',
          fallback: [],
          format: (results) => results.map((result) => result.slug),
          queryFunction: async (target, context) => {
            const ignoreSlugs = ['home-page'];
            const [popular] = await context.hooks.fetch('popular-documents', { limit: 5 }, context);
            const slugs = `"${popular.map(({ slug }) => slug).join('", "')}"`;
            const query = `SELECT 'slug', 'title' FROM documents WHERE slug NOT_IN (${ignoreSlugs}) AND slug IN (${slugs}) ORDER BY updateDate DESC LIMIT 5`;
            const [results] = await context.hooks.fetch('storage-query', query);
            return [results];
          },
        }
      ],
    },
  },

  // Middleware Configuration in the form of ['function', 'param1', 'param2', ...]
  middleware: [
    ['disable', 'x-powered-by'],
    ['enable', 'view cache'],
    ['set', 'views', path.join(`${__dirname}/themes/`, 'default', 'templates')],

    // EJS Specific Setup
    ['use', layouts],
    ['set', 'layout extractScripts', true],
    ['set', 'layout extractStyles', true],
    // If you use the `.ejs` extension use the below:
    // ['set', 'view engine', 'ejs'],
    // I prefer using `.html` templates:
    ['set', 'view engine', 'html'],
    ['engine', 'html', ejs.renderFile],
  ],

  // Override route handlers
  homeRoute: (request, response, next) => { ... },
  tagIndexRoute: (request, response, next) => { ... },
  tagRoute: (request, response, next) => { ... },
  searchRoute: (request, response, next) => { ... },
  editRoute: (request, response, next) => { ... },
  deleteRoute: (request, response, next) => { ... },
  saveRoute: (request, response, next) => { ... },
  saveNewRoute: (request, response, next) => { ... },
  newRoute: (request, response, next) => { ... },
  detailRoute: (request, response, next) => { ... },
  previewRoute: (request, response, next) => { ... },
  historyIndexRoute: (request, response, next) => { ... },
  historyDetailRoute: (request, response, next) => { ... },
  historyRestoreRoute: (request, response, next) => { ... },
  notFoundRoute: (request, response, next) => { ... },
  saveValidRoute: (request, response, next) => { ... },

  // Custom per route middleware, in the order they should be used
  routeMiddleware: {
    home: [],
    tagIndex: [],
    tag: [],
    search: [],
    notFound: [],
    create: [],
    saveNew: [],
    preview: [],
    edit: [],
    delete: [],
    historyIndex: [],
    historyDetail: [],
    historyRestore: [],
    save: [],
    detail: [],
  },
};

export default config;

Use in an example Express.js app:

// Server
import express from 'express';

// Reference the Uttori Wiki middleware
import { wiki as middleware } from '@uttori/wiki';

// Pull in our custom config, example above
import config from './config.js';

// Initilize Your app
const app = express();

// Setup the app
app.set('port', process.env.PORT || 8000);
app.set('ip', process.env.IP || '127.0.0.1');

// Setup Express
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));

// Setup the wiki, could also mount under a sub directory path with other applications
app.use('/', middleware(config));

// Listen for connections
app.listen(app.get('port'), app.get('ip'), () => {
  console.log('✔ listening at %s:%d', app.get('ip'), app.get('port'));
});

Events

The following events are avaliable to hook into through plugins and are used in the methods below:

| Name | Type | Returns | Description | |------------------------------|------------|---------------------------|-------------| | bind-routes | dispatch | | Called after the default routes are bound to the server. | | document-delete | dispatch | | Called when a document is about to be deleted. | | document-save | filter | Uttori Document | Called when a document is about to be saved. | | render-content | filter | HTML Content | Called when content is being prepared to be shown. | | render-search-results | filter | Array of Uttori Documents | Called when search results have been collected and is being prepared to be shown. | | validate-config | dispatch | | Called after initial configuration validation. | | validate-invalid | dispatch | | Called when a document is found invalid (spam?). | | validate-valid | dispatch | | Called when a document is found to be valid. | | validate-save | validate | Boolean | Called before saving a document to validate the document. | | view-model-detail | filter | View Model | Called when rendering the detail page just before being shown. | | view-model-edit | filter | View Model | Called when rendering the edit page just before being shown. | | view-model-error-404 | filter | View Model | Called when rendering a 404 Not Found error page just before being shown. | | view-model-history-detail | filter | View Model | Called when rendering a history detail page just before being shown. | | view-model-history-index | filter | View Model | Called when rendering a history index page just before being shown. | | view-model-history-restore | filter | View Model | Called when rendering a history restore page just before being shown. | | view-model-home | filter | View Model | Called when rendering the home page just before being shown. | | view-model-metadata | filter | View Model | Called after the initial view model metadata is setup. | | view-model-new | filter | View Model | Called when rendering the new document page just before being shown. | | view-model-search | filter | View Model | Called when rendering a search result page just before being shown. | | view-model-tag-index | filter | View Model | Called when rendering the tag index page just before being shown. | | view-model-tag | filter | View Model | Called when rendering a tag detail page just before being shown. |


API Reference

Classes

Functions

Typedefs

UttoriWiki

UttoriWiki is a fast, simple, wiki knowledge base.

Kind: global class
Properties

| Name | Type | Description | | --- | --- | --- | | config | UttoriWikiConfig | The configuration object. | | hooks | EventDispatcher | The hook / event dispatching object. |

new UttoriWiki(config, server)

Creates an instance of UttoriWiki.

| Param | Type | Description | | --- | --- | --- | | config | UttoriWikiConfig | A configuration object. | | server | module:express~Application | The Express server instance. |

Example (Init UttoriWiki)

const server = express();
const wiki = new UttoriWiki(config, server);
server.listen(server.get('port'), server.get('ip'), () => { ... });

uttoriWiki.config : UttoriWikiConfig

Kind: instance property of UttoriWiki

uttoriWiki.hooks : EventDispatcher

Kind: instance property of UttoriWiki

uttoriWiki.registerPlugins(config)

Registers plugins with the Event Dispatcher.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | config | UttoriWikiConfig | A configuration object. |

uttoriWiki.validateConfig(config)

Validates the config.

Hooks:

  • dispatch - validate-config - Passes in the config object.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | config | UttoriWikiConfig | A configuration object. |

uttoriWiki.buildMetadata(document, [path], [robots]) ⇒ Promise.<UttoriWikiDocumentMetaData>

Builds the metadata for the view model.

Hooks:

  • filter - render-content - Passes in the meta description.

Kind: instance method of UttoriWiki
Returns: Promise.<UttoriWikiDocumentMetaData> - Metadata object.

| Param | Type | Description | | --- | --- | --- | | document | UttoriWikiDocument | object | A UttoriWikiDocument. | | [path] | string | The URL path to build meta data for with leading slash. | | [robots] | string | A meta robots tag value. |

Example

const metadata = await wiki.buildMetadata(document, '/private-document-path', 'no-index');
➜ {
  canonical,   // `${this.config.publicUrl}/private-document-path`
  robots,      // 'no-index'
  title,       // document.title
  description, // document.excerpt || document.content.slice(0, 160)
  modified,    // new Date(document.updateDate).toISOString()
  published,   // new Date(document.createDate).toISOString()
}

uttoriWiki.bindRoutes(server)

Bind the routes to the server. Routes are bound in the order of Home, Tags, Search, Not Found Placeholder, Document, Plugins, Not Found - Catch All

Hooks:

  • dispatch - bind-routes - Passes in the server instance.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | server | module:express~Application | The Express server instance. |

uttoriWiki.home(request, response, next)

Renders the homepage with the home template.

Hooks:

  • filter - render-content - Passes in the home-page content.
  • filter - view-model-home - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.homepageRedirect(request, response, _next)

Redirects to the homepage.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | _next | module:express~NextFunction | The Express Next function. |

uttoriWiki.tagIndex(request, response, next)

Renders the tag index page with the tags template.

Hooks:

  • filter - view-model-tag-index - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.tag(request, response, next)

Renders the tag detail page with tag template. Sets the X-Robots-Tag header to noindex. Attempts to pull in the relevant site section for the tag if defined in the config site sections.

Hooks:

  • filter - view-model-tag - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.search(request, response, next)

Renders the search page using the search template.

Hooks:

  • filter - render-search-results - Passes in the search results.
  • filter - view-model-search - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.edit(request, response, next)

Renders the edit page using the edit template.

Hooks:

  • filter - view-model-edit - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.delete(request, response, next)

Attempts to delete a document and redirect to the homepage. If the config useDeleteKey value is true, the key is verified before deleting.

Hooks:

  • dispatch - document-delete - Passes in the document beind deleted.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.save(request, response, next)

Attempts to update an existing document and redirects to the detail view of that document when successful.

Hooks:

  • validate - validate-save - Passes in the request.
  • dispatch - validate-invalid - Passes in the request.
  • dispatch - validate-valid - Passes in the request.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.saveNew(request, response, next)

Attempts to save a new document and redirects to the detail view of that document when successful.

Hooks:

  • validate - validate-save - Passes in the request.
  • dispatch - validate-invalid - Passes in the request.
  • dispatch - validate-valid - Passes in the request.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.create(request, response, next)

Renders the creation page using the edit template.

Hooks:

  • filter - view-model-new - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.detail(request, response, next)

Renders the detail page using the detail template.

Hooks:

  • fetch - storage-get - Get the requested content from the storage.
  • filter - render-content - Passes in the document content.
  • filter - view-model-detail - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.preview(request, response, next)

Renders the a preview of the passed in content. Sets the X-Robots-Tag header to noindex.

Hooks:

  • render-content - render-content - Passes in the request body content.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.historyIndex(request, response, next)

Renders the history index page using the history_index template. Sets the X-Robots-Tag header to noindex.

Hooks:

  • filter - view-model-history-index - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.historyDetail(request, response, next)

Renders the history detail page using the detail template. Sets the X-Robots-Tag header to noindex.

Hooks:

  • render-content - render-content - Passes in the document content.
  • filter - view-model-history-index - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.historyRestore(request, response, next)

Renders the history restore page using the edit template. Sets the X-Robots-Tag header to noindex.

Hooks:

  • filter - view-model-history-restore - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.notFound(request, response, next)

Renders the 404 Not Found page using the 404 template. Sets the X-Robots-Tag header to noindex.

Hooks:

  • filter - view-model-error-404 - Passes in the viewModel.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.saveValid(request, response, next)

Handles saving documents, and changing the slug of documents, then redirecting to the document.

title, excerpt, and content will default to a blank string tags is expected to be a comma delimited string in the request body, "tag-1,tag-2" slug will be converted to lowercase and will use request.body.slug and fall back to request.params.slug.

Hooks:

  • filter - document-save - Passes in the document.

Kind: instance method of UttoriWiki

| Param | Type | Description | | --- | --- | --- | | request | module:express~Request | The Express Request object. | | response | module:express~Response | The Express Response object. | | next | module:express~NextFunction | The Express Next function. |

uttoriWiki.getTaggedDocuments(tag, [limit]) ⇒ Promise.<Array>

Returns the documents with the provided tag, up to the provided limit. This will exclude any documents that have slugs in the config.ignoreSlugs array.

Hooks:

  • fetch - storage-query - Searched for the tagged documents.

Kind: instance method of UttoriWiki
Returns: Promise.<Array> - Promise object that resolves to the array of the documents.

| Param | Type | Default | Description | | --- | --- | --- | --- | | tag | string | | The tag to look for in documents. | | [limit] | number | 1024 | The maximum number of documents to be returned. |

Example

wiki.getTaggedDocuments('example', 10);
➜ [{ slug: 'example', title: 'Example', content: 'Example content.', tags: ['example'] }]

asyncHandler() : AsyncRequestHandler

Kind: global function

UttoriWikiDocument : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | slug | string | The document slug to be used in the URL and as a unique ID. | | title | string | The document title to be used anywhere a title may be needed. | | [image] | string | An image to represent the document in Open Graph or elsewhere. | | [excerpt] | string | A succinct deescription of the document, think meta description. | | content | string | All text content for the doucment. | | [html] | string | All rendered HTML content for the doucment that will be presented to the user. | | createDate | number | The Unix timestamp of the creation date of the document. | | updateDate | number | The Unix timestamp of the last update date to the document. | | tags | Array.<string> | A collection of tags that represent the document. | | [redirects] | Array.<string> | An array of slug like strings that will redirect to this document. Useful for renaming and keeping links valid or for short form WikiLinks. | | [layout] | string | The layout to use when rendering the document. |

UttoriWikiDocumentMetaData : object

Kind: global typedef
Properties

| Name | Type | Description | | --- | --- | --- | | canonical | string | ${this.config.publicUrl}/private-document-path | | robots | string | 'no-index' | | title | string | document.title | | description | string | document.excerpt || document.content.slice(0, 160) | | modified | string | new Date(document.updateDate).toISOString() | | published | string | new Date(document.createDate).toISOString() | | image | string | OpenGraph Image |


Tests

To run the test suite, first install the dependencies, then run npm test:

npm install
DEBUG=Uttori* npm test

Contributors

License

MIT