Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,7 @@ dist
.npmrc
package-lock.json

.vscode
.vscode

.temp
.cache
6 changes: 6 additions & 0 deletions docs/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
!.vuepress/
!.*.js
.cache/
.temp/
node_modules/
dist/
13 changes: 13 additions & 0 deletions docs/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
root: true,
extends: 'vuepress',
overrides: [
{
files: ['*.ts', '*.vue'],
extends: 'vuepress-typescript',
parserOptions: {
project: ['tsconfig.json'],
},
},
],
}
1 change: 1 addition & 0 deletions docs/.node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
10 changes: 10 additions & 0 deletions docs/.vuepress/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type {Router} from "vue-router";

interface ClientConfig {
enhance?: (context: {
app: any;
router: Router;
siteData: any;
}) => void | Promise<void>;
setup?: () => void;
}
28 changes: 28 additions & 0 deletions docs/.vuepress/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { dl } from "@mdit/plugin-dl";
import viteBundler from "@vuepress/bundler-vite";
import vueDevTools from 'vite-plugin-vue-devtools'
import { defineUserConfig } from "vuepress";
import { hopeTheme } from "vuepress-theme-hope";
import { themeOptions } from "./configs/theme";
import { linkCheckPlugin } from "./markdown/linkCheck";
import { replaceLinkPlugin } from "./markdown/replaceLink";


export default defineUserConfig({
base: "/",
dest: "public",
title: "Docs",
description: "Event-native database",
bundler: viteBundler({ viteOptions: { plugins: [vueDevTools(),], } }),
markdown: { importCode: false },
extendsMarkdown: md => {
md.use(linkCheckPlugin);
md.use(replaceLinkPlugin, {
replaceLink: (link: string, _) => link
.replace("@api", "/api")
.replace("@server/", "/server/{version}/")
});
md.use(dl);
},
theme: hopeTheme(themeOptions, { custom: true }),
});
36 changes: 36 additions & 0 deletions docs/.vuepress/configs/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type {ThemeOptions} from "vuepress-theme-hope";

export const themeOptions: ThemeOptions = {
logo: "/Kurrent Logo - Plum.svg",
logoDark: "/Kurrent Logo - White.svg",
docsDir: 'docs',
editLink: false,
lastUpdated: true,
toc: true,
repo: "https://github.com/kurrent-io",
repoLabel: "GitHub",
repoDisplay: true,
contributors: false,
pure: false,
darkmode:"toggle",
headerDepth: 3,
pageInfo: false,
markdown: {
figure: true,
imgLazyload: true,
imgMark: true,
imgSize: true,
tabs: true,
codeTabs: true,
component: true,
mermaid: true,
highlighter: {
type: "shiki",
themes: {
light: "one-light",
dark: "one-dark-pro",
}
}
}
}

6 changes: 6 additions & 0 deletions docs/.vuepress/lib/externalPlaceholders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const externalPlaceholders = ["@samples", "@clients"];

export function isKnownPlaceholder(placeholder: string): boolean {
const known = externalPlaceholders.find(x => x == placeholder);
return known !== undefined;
}
12 changes: 12 additions & 0 deletions docs/.vuepress/lib/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default {
error(message: string) {
console.log("\x1b[41m%s\x1b[0m", ' ERROR ', `${message}\n`)
process.exit(0)
},
info(message: string) {
console.log("\x1b[44m%s\x1b[0m", ' INFO ', `${message}\n`)
},
success(message: string) {
console.log("\x1b[42m\x1b[30m%s\x1b[0m", ' DONE ', `${message}\n`)
}
}
18 changes: 18 additions & 0 deletions docs/.vuepress/lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type {NavItemOptions, SidebarLinkOptions} from "vuepress-theme-hope";

export interface EsSidebarGroupOptions extends NavItemOptions {
group?: string;
collapsible?: boolean;
title?: string;
version?: string;
prefix?: string;
link?: string;
children: EsSidebarItemOptions[] | string[];
}

export type EsSidebarItemOptions = SidebarLinkOptions | EsSidebarGroupOptions | string;
export type EsSidebarArrayOptions = EsSidebarItemOptions[];
export type EsSidebarObjectOptions = Record<string, EsSidebarArrayOptions | "structure">;
export type EsSidebarOptions = EsSidebarArrayOptions | EsSidebarObjectOptions;

export type ImportedSidebarArrayOptions = EsSidebarGroupOptions[];
15 changes: 15 additions & 0 deletions docs/.vuepress/lib/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const versionRegex = /v((\d+\.)?(\d+\.)?(\*|\d+))/;
const nightly = "nightly";
const v = {
isVersion: (v: string) => versionRegex.test(v),
parseVersion: (v: string) => versionRegex.exec(v),
getVersion: (path: string): string | undefined => {
if (path.includes(nightly)) {
return nightly;
}
const ref = path.split("#")[0];
const split = ref.split("/");
return split.find(x => v.isVersion(x));
}
};
export default v;
135 changes: 135 additions & 0 deletions docs/.vuepress/lib/versioning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as fs from "fs";
import {path} from 'vuepress/utils';
import log from "./log";
import {createRequire} from 'node:module';
// import references from "../versions.json";
import type {
EsSidebarGroupOptions, EsSidebarObjectOptions,
ImportedSidebarArrayOptions
} from "./types";

interface VersionDetail {
version: string,
path: string,
startPage: string
}

interface Version {
id: string,
group: string,
basePath: string,
versions: VersionDetail[]
}

const createSidebarItem = (item: EsSidebarGroupOptions, path: string, version: string, group: string): EsSidebarGroupOptions => {
const xp = `/${path}/`;
let ch = item.children as string[];
if (item.collapsible !== undefined) {
ch = ch.map(x => !x.startsWith('../') ? '../' + x : x);
}
const childPath = item.prefix ? `/${path}${item.prefix}` : xp;
const children = ch.map(x => x.split(xp).join(""));
return {
...item,
children: children.map(x => `${childPath}${x}`),
prefix: undefined,
group,
version,
text: item.text || item.title || ""
}
}

export class versioning {
versions: Version[] = [];

constructor() {
// const require = createRequire(import.meta.url)
// references.forEach(p => {
// const fileName = path.resolve(__dirname, p);
// if (fs.existsSync(fileName)) {
// log.info(`Importing versions from ${fileName}`);
// const list: Version[] = require(fileName);
// list.forEach(v => {
// const existing = this.versions.find(x => x.id === v.id);
// if (existing === undefined) {
// this.versions.push(v);
// } else {
// existing.versions.push(...v.versions);
// }
// });
// } else {
// log.info(`File ${fileName} doesn't exist, ignoring`);
// }
// });
}

get latestSemver(): string {
const serverDocs = this.versions.find(v => v.id === "server");
if (!serverDocs) {
throw new Error("Server docs not found");
}
return serverDocs.versions[0].path;
}

// latest stable release
get latest(): string {
const serverDocs = this.versions.find(v => v.id === "server");
if (!serverDocs) {
throw new Error("Server docs not found");
}
return `${serverDocs.basePath}/${serverDocs.versions[0].path}`;
}

get all() {
return this.versions
}

// Generate a single object that represents all versions from each sidebar
getSidebars() {
let sidebars: EsSidebarObjectOptions = {};
const require = createRequire(import.meta.url);

this.versions.forEach(version => {
version.versions.forEach(v => {
const p = `${version.basePath}/${v.path}`;
const sidebarPath = path.resolve(__dirname, `../../${p}`);
const sidebarBase = path.join(sidebarPath, "sidebar");
const sidebarJs = `${sidebarBase}.js`;
const sidebarCjs = `${sidebarBase}.cjs`;
fs.copyFileSync(sidebarJs, sidebarCjs);
log.info(`Importing sidebar from ${sidebarJs}`);
const sidebar: ImportedSidebarArrayOptions = require(sidebarCjs);
sidebars[`/${p}/`] = sidebar.map(item => createSidebarItem(item, p, v.version, version.group));
fs.rmSync(sidebarCjs);
});
})

console.log(JSON.stringify(sidebars, null, 2));
return sidebars;
}

version(id: string) {
const ret = this.versions.find(x => x.id === id);
if (ret === undefined) log.error(`Version ${id} not defined`);
return ret;
}

// Build dropdown items for each version
linksFor(id: string, url?: string) {
const links: { text: string, link: string }[] = [];
const version = this.version(id);
if (version === undefined) return links;

version.versions.forEach(v => {
const path = `${version.basePath}/${v.path}`;
const pageUrl = (url ? url : v.startPage ? v.startPage : "");
const link = `/${path}/${pageUrl}`;
const item = {text: v.version, link: link};
links.push(item);
});

return links;
}
}

export const instance: versioning = new versioning();
90 changes: 90 additions & 0 deletions docs/.vuepress/markdown/linkCheck/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {type PluginSimple} from "markdown-it";
import {fs, logger, path} from "vuepress/utils";
import type {MarkdownEnv, MdToken} from "../types";

function findAnchor(filename: string, anchor: string): boolean {
const asAnchor = (header: string) => header
.replace(/[^\w\s\-']/gi, "")
.trim()
.toLowerCase()
// @ts-ignore
.replaceAll(" ", "-")
.replaceAll("'", "-");

// const enableLogs = filename.endsWith("v24.6/operations.md");

const href = `<a id="${anchor}">`;
const lines = fs.readFileSync(filename).toString().split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.includes(href)) return true;

if (line.charAt(0) != "#") continue;

const lineAnchor = asAnchor(line);
// if (enableLogs) logger.tip(lineAnchor)
if (lineAnchor === anchor || lineAnchor.replace("--", "-") === anchor) return true;
}
return false;
}

function checkLink(token: MdToken, attrName: string, env: MarkdownEnv) {
const href = token.attrGet(attrName);
if (href === null) return;
if (href.startsWith("http") || href.endsWith(".html")) return;
ensureLocalLink(href, env, true);
}

export function ensureLocalLink(href: string, env: MarkdownEnv, ignorePlaceholders: boolean) {
if (ignorePlaceholders && (href.startsWith("@") || env.filePathRelative!.startsWith("samples"))) return;
// check the link
const split = href.split("#");
const currentPath = href[0] == "/" ? path.resolve(__dirname, "../../..") : path.dirname(env.filePath!);
const p = path.join(currentPath, split[0]);
fs.stat(p, (err, stat) => {
if (err != null) {
logger.error(`Broken link in ${env.filePathRelative}\r\nto: ${split[0]}`);
return;
}
let pathToCheck = p;
if (stat.isDirectory()) {
if (split[0] !== "") {
logger.error(`Link to directory in ${env.filePathRelative}\r\nto: ${href}`);
return;
}
pathToCheck = env.filePath!;
}
if (split.length > 1) {
const anchorResolved = findAnchor(pathToCheck, split[1]);
if (!anchorResolved) {
logger.error(`Broken anchor link in ${env.filePathRelative}: ${split[1]} in file ${pathToCheck}`);
}
}
});
}

export const linkCheckPlugin: PluginSimple = (md) => {
md.core.ruler.after(
"inline",
"link-check",
(state) => {
state.tokens.forEach((blockToken) => {
if (!(blockToken.type === "inline" && blockToken.children)) {
return;
}

blockToken.children.forEach((token) => {
const type = token.type;
switch (type) {
case "link_open":
checkLink(token, "href", state.env);
break;
case "image":
checkLink(token, "src", state.env)
break;
}
})
})
}
)
}
Loading
Loading