diff --git a/.eslintignore b/.eslintignore
index d4b782d..7797a8c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -3,4 +3,4 @@ coverage
site/themes/*
convert
node_modules
-types/*
+dist/*
diff --git a/.eslintrc b/.eslintrc
index 2f40d26..28a90d2 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -5,22 +5,22 @@
"plugin:import/recommended",
"plugin:jsdoc/recommended",
"plugin:jsx-a11y/recommended",
- "plugin:node/recommended",
+ "plugin:n/recommended",
"plugin:optimize-regex/all",
- "plugin:ramda/recommended",
- "plugin:security/recommended",
- "plugin:sonarjs/recommended"
+ "plugin:security/recommended-legacy",
+ "plugin:sonarjs/recommended",
+ "plugin:@typescript-eslint/recommended-type-checked"
],
"plugins": [
+ "@typescript-eslint",
"anti-trojan-source",
"ava",
"import",
"jsdoc",
"jsx-a11y",
"no-inferred-method-name",
- "node",
+ "n",
"optimize-regex",
- "ramda",
"security",
"sonarjs",
"xss"
@@ -33,17 +33,23 @@
"sinon": false,
"expect": true
},
+ "parser": "@typescript-eslint/parser",
"parserOptions": {
- "ecmaVersion": 2022,
- "requireConfigFile": false
+ "ecmaVersion": "latest",
+ "project": "./tsconfig.json",
+ "requireConfigFile": false,
+ "sourceType": "module"
},
"rules": {
+ "@typescript-eslint/no-unsafe-argument": "warn",
+ "@typescript-eslint/no-unsafe-assignment": "warn",
+ "@typescript-eslint/no-unsafe-call": "warn",
+ "@typescript-eslint/no-unsafe-member-access": "warn",
+ "@typescript-eslint/no-unsafe-return": "warn",
"anti-trojan-source/no-bidi": "error",
+ "ava/no-only-test": "warn",
"camelcase": 0,
"consistent-return": ["warn", { "treatUndefinedAsUnspecified": false }],
- "eslint-comments/no-use": 0,
- "filenames/match-regex": 0,
- "global-require": 0,
"import/no-commonjs": 0,
"import/no-dynamic-require": 0,
"import/no-extraneous-dependencies": [
@@ -53,10 +59,10 @@
"peerDependencies": true
}
],
+ "import/extensions": ["warn", "ignorePackages"],
"import/no-unresolved": 0,
"max-len": 0,
"no-empty": ["error", { "allowEmptyCatch": true }],
- "no-inferred-method-name/no-inferred-method-name": "error",
"no-param-reassign": 0,
"no-plusplus": 0,
"no-restricted-syntax": [
@@ -75,18 +81,28 @@
}
],
"no-underscore-dangle": 0,
- "no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_", "caughtErrors": "none" }],
- "node/no-missing-require": 0,
- "node/no-unpublished-require": 0,
+ "no-unused-vars": 0,
+ "@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_", "caughtErrors": "none" }],
"object-curly-newline": 0,
"optimize-regex/optimize-regex": "warn",
- "prettier/prettier": 0,
"security/detect-non-literal-fs-filename": 0,
"security/detect-non-literal-require": 0,
"security/detect-object-injection": 0,
"sonarjs/cognitive-complexity": 0,
"sonarjs/no-duplicate-string": 0
},
+ "overrides": [
+ {
+ "files": ["**/*.{spec,test}.*", "test/_helpers/*.*"],
+ "rules": {
+ "@typescript-eslint/no-unsafe-argument": 0,
+ "@typescript-eslint/no-unsafe-assignment": 0,
+ "@typescript-eslint/no-unsafe-call": 0,
+ "@typescript-eslint/no-unsafe-member-access": 0,
+ "@typescript-eslint/no-unsafe-return": 0
+ }
+ }
+ ],
"settings": {
"jsdoc": {
"mode": "typescript"
diff --git a/.nvmrc b/.nvmrc
index f0b10f1..790e110 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v16.13.1
+v20.10.0
diff --git a/.travis.yml b/.travis.yml
index 175ec5b..fb4fc61 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,6 @@
language: node_js
node_js:
- - "16"
- - "18"
+ - "20"
install:
- npm ci
@@ -11,10 +10,8 @@ cache:
- "$HOME/.npm"
script:
- - npm install -g coveralls
- npm run lint
- npm run validate --prod
- - npm run test && nyc report --reporter=text-lcov | coveralls
branches:
only:
diff --git a/.tsconfig.json b/.tsconfig.json
deleted file mode 100644
index c0cdcb1..0000000
--- a/.tsconfig.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "include": [
- "node_modules/@uttori/**/src/*",
- "src/**/*"
- ],
- "exclude": [
- "node_modules",
- "test"
- ],
- "compilerOptions": {
- "allowJs": true,
- "checkJs": true,
- "declaration": true,
- "downlevelIteration": true,
- "emitDeclarationOnly": true,
- "extendedDiagnostics": true,
- "moduleResolution": "node",
- "noEmit": false,
- "outFile": "types/index.d.ts",
- "removeComments": true,
- "sourceMap": true,
- "strict": false,
- "target": "esnext",
- "skipLibCheck": true
- }
-}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd0c2a4..a689e52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,37 @@
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
+## [6.0.0](https://github.com/uttori/uttori-wiki/compare/v5.2.2...v6.0.0) - 2023-12-22
+
+- 💥 BREAKING CHANGES!
+- 💥 Rename config key: `home_page` to `homePage`
+- 💥 Rename config key: `ignore_slugs` to `ignoreSlugs`
+- 💥 Rename config key: `home_page` to `excerptLength`
+- 💥 Rename config key: `excerpt_length` to `homePage`
+- 💥 Rename config key: `site_url` to `publicUrl`
+- 💥 Rename config key: `theme_dir` to `themePath`
+- 💥 Rename config key: `public_dir` to `publicPath`
+- 💥 Rename config key: `use_delete_key` to `useDeleteKey`
+- 💥 Rename config key: `delete_key` to `deleteKey`
+- 💥 Rename config key: `use_edit_key` to `useEditKey`
+- 💥 Rename config key: `edit_key` to `editKey`
+- 💥 Rename config key: `public_history` to `publicHistory`
+- 💥 Rename config key: `handle_not_found` to `handleNotFound`
+- 💥 Rename config key: `use_cache` to `useCache`
+- 💥 Rename config key: `cache_short` to `cacheShort`
+- 💥 Rename config key: `cache_long` to `cacheLong`
+- 💥 Removed many configuration options that were not being used or items that should be theme specific: `site_title`, `site_header`, `site_footer`, `site_sections`, `site_locale`, `site_twitter_site`, `site_twitter_creator`, `site_image`
+- 🧰 Add support for setting the `routes` for search & tags
+- 🧰 Add support for setting the `titles` for search & tags
+- 🧰 Added support for `allowCRUDRoutes` to disable the CRUD routes for a read-only wiki
+- 🧰 Added support for `ignoreTags` to ignore documents with specific tags
+- 🧰 Remove support for CommonJS, now requires ESM support
+- Change the `detailRoute` route path matcher to `/:slug*?` to allow for nested routes with the use of overriding `detailRoute` and handling the `request.params.slug` value accordingly`
+- 🎁 Update dependencies
+- 🛠 Standardize types
+- 🛠 Update ESLint configuration
+- 🛠 Update documentation
+
## [5.2.2](https://github.com/uttori/uttori-wiki/compare/v5.2.1...v5.2.2) - 2023-04-14
- 🛠 Overhaul types and fix some type related warnings.
diff --git a/LICENSE b/LICENSE
index 8f72938..85aae95 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018-2021 Matthew Callis
+Copyright (c) 2018-2023 Matthew Callis
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index f203aa3..de15498 100644
--- a/README.md
+++ b/README.md
@@ -30,53 +30,29 @@ Please see `src/config.js` or [the config doc](https://github.com/uttori/uttori-
- [@uttori/plugin-analytics-json-file](https://github.com/uttori/uttori-plugin-analytics-json-file)
```javascript
-const { Plugin: StorageProvider } = require('@uttori/storage-provider-json-file');
-const { Plugin: SearchProvider } = require('@uttori/search-provider-lunr');
+import { Plugin: StorageProvider } from '@uttori/storage-provider-json-file';
+import { Plugin: SearchProvider } from '@uttori/search-provider-lunr';
-const AnalyticsPlugin = require('@uttori/plugin-analytics-json-file');
-const MarkdownItRenderer = require('@uttori/plugin-renderer-markdown-it');
-const ReplacerRenderer = require('@uttori/plugin-renderer-replacer');
-const MulterUpload = require('@uttori/plugin-upload-multer');
-const SitemapGenerator = require('@uttori/plugin-generator-sitemap');
+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 = {
- site_title: 'Uttori Wiki Demo',
- site_header: 'Uttori Wiki Demo',
- site_footer: 'Uttori Wiki Demo | ✨',
- site_sections: [
- {
- title: 'Section One',
- description: 'An example section.',
- tag: 'examples',
- },
- {
- title: 'Section Two',
- description: 'A section with something already in it.',
- tag: 'reference',
- },
- {
- title: 'Section Three',
- description: 'A third example section.',
- tag: 'tutorial',
- },
- ],
- home_page: 'home-page',
- ignore_slugs: ['home-page'],
- excerpt_length: 400,
- site_url: 'http://127.0.0.1:8000/wiki',
- theme_dir: path.join(__dirname, 'theme'),
- public_dir: path.join(__dirname, 'theme', 'public'),
- use_delete_key: false,
- delete_key: process.env.DELETE_KEY || '',
- use_edit_key: false,
- edit_key: process.env.EDIT_KEY || '',
- public_history: true,
+ 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: [],
- use_meta_data: true,
- site_description: 'An example Wiki using the Uttori Wiki library.',
- site_locale: 'en_US',
- site_twitter_site: '@twitter',
- site_twitter_creator: '@twitter',
// Plugins
plugins: [
@@ -92,17 +68,13 @@ const config = {
// Use the JSON to Disk Storage Provider
[StorageProvider.configKey]: {
// Path in which to store content (markdown files, etc.)
- content_dir: `${__dirname}/content`,
+ contentDirectory: `${__dirname}/content`,
// Path in which to store content history (markdown files, etc.)
- history_dir: `${__dirname}/content/history`,
+ historyDirectory: `${__dirname}/content/history`,
// File Extension
extension: 'json',
-
- // JSON stringify parameter for formatting output
- spaces_article: 2,
- spaces_history: 2,
},
// Use the Lunr Search Provider
@@ -111,7 +83,7 @@ const config = {
lunr_locales: [],
// Ignore Slugs
- ignore_slugs: ['home-page'],
+ ignoreSlugs: ['home-page'],
},
// Plugin: Analytics with JSON Files
@@ -236,6 +208,49 @@ const config = {
],
},
+ // 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'],
@@ -291,20 +306,20 @@ const config = {
},
};
-module.exports = config;
+export default config;
```
Use in an example Express.js app:
```javascript
// Server
-const express = require('express');
+import express from 'express';
// Reference the Uttori Wiki middleware
-const { wiki } = require('@uttori/wiki');
+import { wiki as middleware } from '@uttori/wiki';
// Pull in our custom config, example above
-const config = require('./config.js');
+import config from './config.js';
// Initilize Your app
const app = express();
@@ -318,7 +333,7 @@ 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('/', wiki(config));
+app.use('/', middleware(config));
// Listen for connections
app.listen(app.get('port'), app.get('ip'), () => {
@@ -369,9 +384,7 @@ The following events are avaliable to hook into through plugins and are used in
## Functions
-- debug() :
function
-
-- asyncHandler() :
function
+- asyncHandler() :
AsyncRequestHandler
@@ -380,6 +393,8 @@ The following events are avaliable to hook into through plugins and are used in
- UttoriWikiDocument :
object
+- UttoriWikiDocumentMetaData :
object
+
@@ -402,7 +417,7 @@ UttoriWiki is a fast, simple, wiki knowledge base.
* [.hooks](#UttoriWiki+hooks) : EventDispatcher
* [.registerPlugins(config)](#UttoriWiki+registerPlugins)
* [.validateConfig(config)](#UttoriWiki+validateConfig)
- * [.buildMetadata(document, [path], [robots])](#UttoriWiki+buildMetadata) ⇒ Promise.<object>
+ * [.buildMetadata(document, [path], [robots])](#UttoriWiki+buildMetadata) ⇒ [Promise.<UttoriWikiDocumentMetaData>
](#UttoriWikiDocumentMetaData)
* [.bindRoutes(server)](#UttoriWiki+bindRoutes)
* [.home(request, response, next)](#UttoriWiki+home)
* [.homepageRedirect(request, response, _next)](#UttoriWiki+homepageRedirect)
@@ -432,7 +447,7 @@ Creates an instance of UttoriWiki.
| Param | Type | Description |
| --- | --- | --- |
| config | UttoriWikiConfig
| A configuration object. |
-| server | Application
| The Express server instance. |
+| server | module:express~Application
| The Express server instance. |
**Example** *(Init UttoriWiki)*
```js
@@ -475,26 +490,26 @@ Hooks:
-### uttoriWiki.buildMetadata(document, [path], [robots]) ⇒ Promise.<object>
+### uttoriWiki.buildMetadata(document, [path], [robots]) ⇒ [Promise.<UttoriWikiDocumentMetaData>
](#UttoriWikiDocumentMetaData)
Builds the metadata for the view model.
Hooks:
- `filter` - `render-content` - Passes in the meta description.
**Kind**: instance method of [UttoriWiki
](#UttoriWiki)
-**Returns**: Promise.<object>
- Metadata object.
+**Returns**: [Promise.<UttoriWikiDocumentMetaData>
](#UttoriWikiDocumentMetaData) - Metadata object.
-| Param | Type | Default | Description |
-| --- | --- | --- | --- |
-| document | [UttoriWikiDocument
](#UttoriWikiDocument) \| object
| | A UttoriWikiDocument. |
-| [path] | string
| "''"
| The URL path to build meta data for. |
-| [robots] | string
| "''"
| A meta robots tag value. |
+| Param | Type | Description |
+| --- | --- | --- |
+| document | [UttoriWikiDocument
](#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**
```js
const metadata = await wiki.buildMetadata(document, '/private-document-path', 'no-index');
➜ {
- canonical, // `${this.config.site_url}/private-document-path`
+ canonical, // `${this.config.publicUrl}/private-document-path`
robots, // 'no-index'
title, // document.title
description, // document.excerpt || document.content.slice(0, 160)
@@ -515,7 +530,7 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| server | Application
| The Express server instance. |
+| server | module:express~Application
| The Express server instance. |
@@ -530,9 +545,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -543,9 +558,9 @@ Redirects to the homepage.
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| _next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| _next | module:express~NextFunction
| The Express Next function. |
@@ -559,9 +574,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -577,9 +592,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -594,9 +609,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -610,15 +625,15 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| 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 `use_delete_key` value is true, the key is verified before deleting.
+If the config `useDeleteKey` value is true, the key is verified before deleting.
Hooks:
- `dispatch` - `document-delete` - Passes in the document beind deleted.
@@ -627,9 +642,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -645,9 +660,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -663,9 +678,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -679,9 +694,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -697,9 +712,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -714,9 +729,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -731,9 +746,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -749,9 +764,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -766,9 +781,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -783,9 +798,9 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| request | module:express~Request
| The Express Request object. |
+| response | module:express~Response
| The Express Response object. |
+| next | module:express~NextFunction
| The Express Next function. |
@@ -803,15 +818,15 @@ Hooks:
| Param | Type | Description |
| --- | --- | --- |
-| request | Request
| The Express Request object. |
-| response | Response
| The Express Response object. |
-| next | function
| The Express Next function. |
+| 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.ignore_slugs` array.
+This will exclude any documents that have slugs in the `config.ignoreSlugs` array.
Hooks:
- `fetch` - `storage-query` - Searched for the tagged documents.
@@ -829,13 +844,9 @@ Hooks:
wiki.getTaggedDocuments('example', 10);
➜ [{ slug: 'example', title: 'Example', content: 'Example content.', tags: ['example'] }]
```
-
-
-## debug() : function
-**Kind**: global function
-## asyncHandler() : function
+## asyncHandler() : AsyncRequestHandler
**Kind**: global function
@@ -848,7 +859,7 @@ wiki.getTaggedDocuments('example', 10);
| 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. |
+| [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. |
@@ -856,6 +867,22 @@ wiki.getTaggedDocuments('example', 10);
| 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. |
+
+
+## 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 |
+
* * *
diff --git a/dist/config.d.ts b/dist/config.d.ts
new file mode 100644
index 0000000..afe47e5
--- /dev/null
+++ b/dist/config.d.ts
@@ -0,0 +1,210 @@
+export default config;
+export type UttoriWikiConfig = {
+ /**
+ * Useful for development environments.
+ */
+ production?: boolean;
+ /**
+ * Slug of the root `/` page document.
+ */
+ homePage?: string;
+ /**
+ * Slugs to ignore in search & filtered documents, default is 'home-page';
+ */
+ ignoreSlugs: string[];
+ /**
+ * Tags to ignore when generating the tags page, default is an empty array;
+ */
+ ignoreTags: string[];
+ /**
+ * Excerpt length, used in search result previews.
+ */
+ excerptLength?: number;
+ /**
+ * Application base URL. Used for canonical URLs and redirects, do not include a trailing slash.
+ */
+ publicUrl?: string;
+ /**
+ * The object containing the route strings for search & tags.
+ */
+ routes: Record;
+ /**
+ * The object containing the default titles for search & tags.
+ */
+ titles: Record;
+ /**
+ * Specify the path to the theme directory, no trailing slash.
+ */
+ themePath?: string;
+ /**
+ * Path to the static file directory for themes, no trailing slash
+ */
+ publicPath: string;
+ /**
+ * Enable creation, deletion and editing routes.
+ */
+ allowCRUDRoutes?: boolean;
+ /**
+ * Enable hiding document deletion behind a private key.
+ */
+ useDeleteKey?: boolean;
+ /**
+ * Key used for verifying document deletion.
+ */
+ deleteKey: string | undefined;
+ /**
+ * Enable hiding document modification behind a private key.
+ */
+ useEditKey?: boolean;
+ /**
+ * Key used for verifying document modification.
+ */
+ editKey?: string | undefined;
+ /**
+ * Allow access to history URLs.
+ */
+ publicHistory?: boolean;
+ /**
+ * Allows the middleware to capture fall through routes as a `404 not found` handler when enabled.
+ */
+ handleNotFound?: boolean;
+ /**
+ * =[] List of allowed custom values to set on a document. `title`, `excerpt`, `content`, `slug`, and `tags` are always allowed.
+ */
+ allowedDocumentKeys: string[];
+ /**
+ * Enables `Cache-control` headers reducing server load, but breaks sessions. Cache is disabled always on the `/edit` and `/new` routes.
+ */
+ useCache?: boolean;
+ /**
+ * Used as the max-age for Cache-control'headers on frequently updated routes: home, tag index, tag details, details & history index
+ */
+ cacheShort?: number;
+ /**
+ * Used as the max-age for Cache-control'headers on seldom updated routes: history details, history restore
+ */
+ cacheLong?: number;
+ /**
+ * A replacement route handler for the home route.
+ */
+ homeRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the tag inded route.
+ */
+ tagIndexRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the tag show route.
+ */
+ tagRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the search route.
+ */
+ searchRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the edit route.
+ */
+ editRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the delete route.
+ */
+ deleteRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the save route.
+ */
+ saveRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the save new handler.
+ */
+ saveNewRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the create route.
+ */
+ newRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the detail route.
+ */
+ detailRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the preview route.
+ */
+ previewRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the history index route.
+ */
+ historyIndexRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the history detail route.
+ */
+ historyDetailRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the history restore route.
+ */
+ historyRestoreRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the 404 not found route.
+ */
+ notFoundRoute?: import("express").RequestHandler;
+ /**
+ * A replacement route handler for the save valid route.
+ */
+ saveValidRoute?: import("express").RequestHandler;
+ /**
+ * A collection of middleware for each route.
+ */
+ routeMiddleware: Record;
+ /**
+ * Collection of Uttori Plugins. Storage Plugins should come before other plugins.
+ */
+ plugins: any[];
+ /**
+ * Middleware Configuration to be passed along to Express in the format of ['use', layouts], ['set', 'layout extractScripts', true], ['engine', 'html', ejs.renderFile].
+ */
+ middleware?: import("../dist/custom.js").UttoriMiddleware[];
+};
+/**
+ * @typedef UttoriWikiConfig
+ * @type {object}
+ * @property {boolean} [production=false] Useful for development environments.
+ * @property {string} [homePage='home-page'] Slug of the root `/` page document.
+ * @property {string[]} ignoreSlugs Slugs to ignore in search & filtered documents, default is 'home-page';
+ * @property {string[]} ignoreTags Tags to ignore when generating the tags page, default is an empty array;
+ * @property {number} [excerptLength=400] Excerpt length, used in search result previews.
+ * @property {string} [publicUrl=''] Application base URL. Used for canonical URLs and redirects, do not include a trailing slash.
+ * @property {Record} routes The object containing the route strings for search & tags.
+ * @property {Record} titles The object containing the default titles for search & tags.
+ * @property {string} [themePath=''] Specify the path to the theme directory, no trailing slash.
+ * @property {string} publicPath Path to the static file directory for themes, no trailing slash
+ * @property {boolean} [allowCRUDRoutes=true] Enable creation, deletion and editing routes.
+ * @property {boolean} [useDeleteKey=false] Enable hiding document deletion behind a private key.
+ * @property {string|undefined} deleteKey Key used for verifying document deletion.
+ * @property {boolean} [useEditKey=false] Enable hiding document modification behind a private key.
+ * @property {string|undefined} [editKey] Key used for verifying document modification.
+ * @property {boolean} [publicHistory=true] Allow access to history URLs.
+ * @property {boolean} [handleNotFound=true] Allows the middleware to capture fall through routes as a `404 not found` handler when enabled.
+ * @property {string[]} allowedDocumentKeys=[] List of allowed custom values to set on a document. `title`, `excerpt`, `content`, `slug`, and `tags` are always allowed.
+ * @property {boolean} [useCache=true] Enables `Cache-control` headers reducing server load, but breaks sessions. Cache is disabled always on the `/edit` and `/new` routes.
+ * @property {number} [cacheShort=(60 * 60)] Used as the max-age for Cache-control'headers on frequently updated routes: home, tag index, tag details, details & history index
+ * @property {number} [cacheLong=(60 * 60 * 24)] Used as the max-age for Cache-control'headers on seldom updated routes: history details, history restore
+ * @property {import("express").RequestHandler} [homeRoute] A replacement route handler for the home route.
+ * @property {import("express").RequestHandler} [tagIndexRoute] A replacement route handler for the tag inded route.
+ * @property {import("express").RequestHandler} [tagRoute] A replacement route handler for the tag show route.
+ * @property {import("express").RequestHandler} [searchRoute] A replacement route handler for the search route.
+ * @property {import("express").RequestHandler} [editRoute] A replacement route handler for the edit route.
+ * @property {import("express").RequestHandler} [deleteRoute] A replacement route handler for the delete route.
+ * @property {import("express").RequestHandler} [saveRoute] A replacement route handler for the save route.
+ * @property {import("express").RequestHandler} [saveNewRoute] A replacement route handler for the save new handler.
+ * @property {import("express").RequestHandler} [newRoute] A replacement route handler for the create route.
+ * @property {import("express").RequestHandler} [detailRoute] A replacement route handler for the detail route.
+ * @property {import("express").RequestHandler} [previewRoute] A replacement route handler for the preview route.
+ * @property {import("express").RequestHandler} [historyIndexRoute] A replacement route handler for the history index route.
+ * @property {import("express").RequestHandler} [historyDetailRoute] A replacement route handler for the history detail route.
+ * @property {import("express").RequestHandler} [historyRestoreRoute] A replacement route handler for the history restore route.
+ * @property {import("express").RequestHandler} [notFoundRoute] A replacement route handler for the 404 not found route.
+ * @property {import("express").RequestHandler} [saveValidRoute] A replacement route handler for the save valid route.
+ * @property {Record} routeMiddleware A collection of middleware for each route.
+ * @property {Array} plugins Collection of Uttori Plugins. Storage Plugins should come before other plugins.
+ * @property {import("../dist/custom.js").UttoriMiddleware[]} [middleware] Middleware Configuration to be passed along to Express in the format of ['use', layouts], ['set', 'layout extractScripts', true], ['engine', 'html', ejs.renderFile].
+ */
+/** @type {UttoriWikiConfig} */
+declare const config: UttoriWikiConfig;
+//# sourceMappingURL=config.d.ts.map
\ No newline at end of file
diff --git a/dist/config.d.ts.map b/dist/config.d.ts.map
new file mode 100644
index 0000000..64ded09
--- /dev/null
+++ b/dist/config.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.js"],"names":[],"mappings":";;;;;iBAGc,OAAO;;;;eACP,MAAM;;;;iBACN,MAAM,EAAE;;;;gBACR,MAAM,EAAE;;;;oBACR,MAAM;;;;gBACN,MAAM;;;;YACN,OAAO,MAAM,EAAE,MAAM,CAAC;;;;YACtB,OAAO,MAAM,EAAE,MAAM,CAAC;;;;gBACtB,MAAM;;;;gBACN,MAAM;;;;sBACN,OAAO;;;;mBACP,OAAO;;;;eACP,MAAM,GAAC,SAAS;;;;iBAChB,OAAO;;;;cACP,MAAM,GAAC,SAAS;;;;oBAChB,OAAO;;;;qBACP,OAAO;;;;yBACP,MAAM,EAAE;;;;eACR,OAAO;;;;iBACP,MAAM;;;;gBACN,MAAM;;;;gBACN,OAAO,SAAS,EAAE,cAAc;;;;oBAChC,OAAO,SAAS,EAAE,cAAc;;;;eAChC,OAAO,SAAS,EAAE,cAAc;;;;kBAChC,OAAO,SAAS,EAAE,cAAc;;;;gBAChC,OAAO,SAAS,EAAE,cAAc;;;;kBAChC,OAAO,SAAS,EAAE,cAAc;;;;gBAChC,OAAO,SAAS,EAAE,cAAc;;;;mBAChC,OAAO,SAAS,EAAE,cAAc;;;;eAChC,OAAO,SAAS,EAAE,cAAc;;;;kBAChC,OAAO,SAAS,EAAE,cAAc;;;;mBAChC,OAAO,SAAS,EAAE,cAAc;;;;wBAChC,OAAO,SAAS,EAAE,cAAc;;;;yBAChC,OAAO,SAAS,EAAE,cAAc;;;;0BAChC,OAAO,SAAS,EAAE,cAAc;;;;oBAChC,OAAO,SAAS,EAAE,cAAc;;;;qBAChC,OAAO,SAAS,EAAE,cAAc;;;;qBAChC,OAAO,MAAM,EAAE,OAAO,SAAS,EAAE,cAAc,EAAE,CAAC;;;;;;;;iBAElD,OAAO,mBAAmB,EAAE,gBAAgB,EAAE;;AA1C5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,+BAA+B;AAC/B,sBADW,gBAAgB,CAgDzB"}
\ No newline at end of file
diff --git a/dist/custom.d.ts b/dist/custom.d.ts
new file mode 100644
index 0000000..ad90e61
--- /dev/null
+++ b/dist/custom.d.ts
@@ -0,0 +1,36 @@
+import { Express } from 'express-serve-static-core';
+
+// https://plusreturn.com/blog/how-to-extend-express-request-interface-in-typescript/
+/** Add wikiFlash to the Request type. */
+declare module 'express-serve-static-core' {
+ interface Request {
+ wikiFlash(key?: string, value?: any): object | any[] | boolean;
+ }
+}
+
+// https://stackoverflow.com/questions/38900537/typescript-extend-express-session-interface-with-own-class
+declare namespace Express {
+ interface CustomSessionFields {
+ myCustomField: string;
+ }
+ type RequestExpress = import('express-serve-static-core').Request;
+ type SessionExpress = import('express-session').Session;
+ type SessionDataExpress = import('express-session').SessionData;
+ export interface RequestExtended extends RequestExpress {
+ session: SessionExpress & Partial & CustomSessionFields
+ }
+}
+
+type UttoriContext = {
+ config: Record;
+ hooks: {
+ on: Function;
+ fetch: Function;
+ };
+}
+type UttoriMiddleware = (string | Function | boolean)[]
+type AsyncRequestHandler = (fn: import('express').RequestHandler) => (request: import('express').Request, response: import('express').Response, next: import('express').NextFunction) => void
+
+type AddQueryOutputToViewModelFormatFunction = (documents:object[]) => object[]
+type AddQueryOutputToViewModelQueryFunction = (target:object, context:UttoriContext) => Promise