Publish src

Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
This commit is contained in:
Joshua Castle
2024-03-24 00:16:33 -07:00
parent d2577f5d28
commit 9167ba6b07
30 changed files with 594 additions and 3 deletions
+1 -1
View File
@@ -26,4 +26,4 @@ lerna-debug.log
packages/docusaurus-playground/static/generated/*
lib/
tsconfig.tsbuildinfo
+6
View File
@@ -0,0 +1,6 @@
import type { LoadContext, Plugin } from '@docusaurus/types';
import { PluginOptions } from './server/types/plugin.types';
export { imageRendererFactory } from './server/imageRenderer.factory';
export * from './server/types';
export type { PluginOptions };
export default function logosTheme(context: LoadContext, options: PluginOptions): Plugin<any>;
+17
View File
@@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.imageRendererFactory = void 0;
const tslib_1 = require("tslib");
const index_1 = require("./server/index");
var imageRenderer_factory_1 = require("./server/imageRenderer.factory");
Object.defineProperty(exports, "imageRendererFactory", { enumerable: true, get: function () { return imageRenderer_factory_1.imageRendererFactory; } });
tslib_1.__exportStar(require("./server/types"), exports);
function logosTheme(context, options) {
return {
name: 'docusaurus-og',
async postBuild(props) {
await (0, index_1.postBuildFactory)(options)(props);
},
};
}
exports.default = logosTheme;
+19
View File
@@ -0,0 +1,19 @@
import { LoadedPlugin, Props } from '@docusaurus/types';
import { ImageGenerator } from './imageGenerator';
import { BlogPageData } from './types/blog.types';
import { ImageRenderer } from './types/image.types';
import { PluginOptions } from './types/plugin.types';
export declare class BlogPlugin {
private context;
private options;
private imageGenerator;
private imageRenderer;
static plugin: string;
pages: Omit<BlogPageData, 'document'>[];
constructor(context: Props, options: PluginOptions, imageGenerator: ImageGenerator, imageRenderer: ImageRenderer);
process: () => Promise<void>;
loadData: () => Promise<void>;
loadInstance: (plugin: LoadedPlugin) => Promise<void>;
generate: () => Promise<void>;
getHtmlPath: (permalink: string, baseUrl?: string) => string;
}
+107
View File
@@ -0,0 +1,107 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlogPlugin = void 0;
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs"));
const path = tslib_1.__importStar(require("path"));
const document_1 = require("./document");
class BlogPlugin {
context;
options;
imageGenerator;
imageRenderer;
static plugin = 'docusaurus-plugin-content-blog';
pages = [];
constructor(context, options, imageGenerator, imageRenderer) {
this.context = context;
this.options = options;
this.imageGenerator = imageGenerator;
this.imageRenderer = imageRenderer;
}
process = async () => {
await this.loadData();
await this.generate();
};
loadData = async () => {
const plugins = this.context.plugins.filter((plugin) => plugin.name === BlogPlugin.plugin);
for (const plugin of plugins) {
await this.loadInstance(plugin);
}
};
loadInstance = async (plugin) => {
const content = plugin.content;
const options = plugin.options;
content.blogListPaginated.forEach((value) => {
this.pages.push({
data: value,
plugin: options,
pageType: 'list',
permalink: value.metadata.permalink,
});
});
content.blogPosts.forEach((post) => {
this.pages.push({
data: post,
plugin: options,
pageType: 'post',
permalink: post.metadata.permalink,
});
});
if (content.blogTagsListPath) {
const filePath = this.getHtmlPath(content.blogTagsListPath);
fs.existsSync(filePath) &&
this.pages.push({
pageType: 'tags',
plugin: options,
data: {
permalink: content.blogTagsListPath,
},
permalink: content.blogTagsListPath,
});
}
if (options.archiveBasePath) {
const permalink = path.join('/', options.routeBasePath, options.archiveBasePath);
fs.existsSync(this.getHtmlPath(permalink)) &&
this.pages.push({
plugin: options,
pageType: 'archive',
data: { permalink: permalink },
permalink,
});
}
{
Object.entries(content.blogTags).map(([key, value]) => {
value.pages.forEach((page) => {
this.pages.push({
pageType: 'tag',
plugin: options,
data: { ...page.metadata, label: value.label },
permalink: page.metadata.permalink,
});
});
});
}
};
generate = async () => {
for (const page of this.pages) {
const document = new document_1.Document(this.getHtmlPath(page.permalink));
await document.load();
if (!document.loaded)
continue;
const image = await this.imageRenderer({
...page,
document,
websiteOutDir: this.context.outDir,
}, this.context);
if (!image) {
await document.write();
continue;
}
const generated = await this.imageGenerator.generate(...image);
await document.setImage(generated.url);
await document.write();
}
};
getHtmlPath = (permalink, baseUrl) => path.join(this.context.outDir, permalink, 'index.html');
}
exports.BlogPlugin = BlogPlugin;
+22
View File
@@ -0,0 +1,22 @@
/// <reference types="@docusaurus/plugin-content-docs/src/plugin-content-docs.js" />
import { PluginOptions as DocsPluginOptions, LoadedVersion } from '@docusaurus/plugin-content-docs';
import { LoadedPlugin, Props } from '@docusaurus/types';
import { ImageGenerator } from './imageGenerator';
import { DocsPageData } from './types/docs.types';
import { ImageRenderer } from './types/image.types';
import { PluginOptions } from './types/plugin.types';
export declare class DocsPlugin {
private context;
private options;
private imageGenerator;
private imageRenderer;
static plugin: string;
docs: Omit<DocsPageData, 'document'>[];
constructor(context: Props, options: PluginOptions, imageGenerator: ImageGenerator, imageRenderer: ImageRenderer);
process: () => Promise<void>;
loadData: () => Promise<void>;
loadInstance: (plugin: LoadedPlugin) => Promise<void>;
loadVersion: (options: DocsPluginOptions, version: LoadedVersion) => Promise<void>;
generate: () => Promise<void>;
getHtmlPath: (doc: Partial<DocsPageData>) => string | undefined;
}
+69
View File
@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DocsPlugin = void 0;
const tslib_1 = require("tslib");
const path = tslib_1.__importStar(require("path"));
const document_1 = require("./document");
class DocsPlugin {
context;
options;
imageGenerator;
imageRenderer;
static plugin = 'docusaurus-plugin-content-docs';
docs = [];
constructor(context, options, imageGenerator, imageRenderer) {
this.context = context;
this.options = options;
this.imageGenerator = imageGenerator;
this.imageRenderer = imageRenderer;
}
process = async () => {
await this.loadData();
await this.generate();
};
loadData = async () => {
const { plugins = [] } = this.context;
const docPlugins = plugins.filter((plugin) => plugin.name === DocsPlugin.plugin);
for (const plugin of docPlugins) {
await this.loadInstance(plugin);
}
};
loadInstance = async (plugin) => {
const content = plugin.content;
const options = plugin.options;
const { loadedVersions } = content;
for (const version of loadedVersions) {
await this.loadVersion(options, version);
}
};
loadVersion = async (options, version) => {
this.docs.push(...version.docs.map((doc) => ({
version,
metadata: doc,
plugin: options,
})));
};
generate = async () => {
for (const doc of this.docs) {
const document = new document_1.Document(this.getHtmlPath(doc));
await document.load();
const image = await this.imageRenderer({
...doc,
document,
websiteOutDir: this.context.outDir,
}, this.context);
if (!image) {
await document.write();
continue;
}
const generated = await this.imageGenerator.generate(...image);
await document.setImage(generated.url);
await document.write();
}
};
getHtmlPath = (doc) =>
// slug is used here instead of permalink because permalink already contains version and locale paths of websiteOutDir
doc.metadata?.slug &&
path.join(this.context.outDir, doc.metadata.slug, 'index.html');
}
exports.DocsPlugin = DocsPlugin;
+13
View File
@@ -0,0 +1,13 @@
import { HTMLElement } from 'node-html-parser';
export declare class Document {
private path;
root: HTMLElement;
loaded: boolean;
constructor(path: string);
load: () => Promise<void>;
write: () => Promise<void>;
setImage: (url: string) => Promise<void>;
get head(): HTMLElement;
private getMeta;
private updateMeta;
}
+51
View File
@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Document = void 0;
const tslib_1 = require("tslib");
const fsp = tslib_1.__importStar(require("fs/promises"));
const node_html_parser_1 = require("node-html-parser");
const IMAGE_META_ELEMENTS = [
['name', 'image'],
['property', 'og:image'],
['name', 'twitter:image'],
];
class Document {
path;
root;
loaded = false;
constructor(path) {
this.path = path;
}
load = async () => {
const htmlString = await fsp.readFile(this.path, 'utf-8');
this.root = (0, node_html_parser_1.parse)(htmlString);
this.loaded = true;
};
write = async () => {
await fsp.writeFile(this.path, Buffer.from(this.root.outerHTML));
};
setImage = async (url) => {
IMAGE_META_ELEMENTS.forEach(([attr, value]) => this.updateMeta(attr, value, {
content: url,
}));
};
get head() {
return this.root.querySelector('head');
}
getMeta(attr, value) {
const { head } = this;
let meta = head.querySelector(`meta[${attr}=${value}]`);
if (!meta) {
meta = new node_html_parser_1.HTMLElement('meta', {}, '', undefined, [0, 0]);
meta.setAttribute(attr, value);
head.appendChild(meta);
}
return meta;
}
updateMeta = (attr, value, attrs) => {
const el = this.getMeta(attr, value);
Object.entries(attrs).forEach(([key, value]) => el.setAttribute(key, value));
return el;
};
}
exports.Document = Document;
+22
View File
@@ -0,0 +1,22 @@
import React from 'react';
import { type SatoriOptions } from 'satori';
export type ImageGeneratorOptions = SatoriOptions;
export type ImageGeneratorResult = {
url: string;
relativePath: string;
absolutePath: string;
};
export declare class ImageGenerator {
private args;
private satori;
private sharp;
private cache;
private outDir;
constructor(args: {
dir: string;
websiteUrl: string;
websiteOutDir: string;
});
init: () => Promise<void>;
generate: (element: React.ReactNode, options: ImageGeneratorOptions) => Promise<ImageGeneratorResult>;
}
+44
View File
@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageGenerator = void 0;
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs"));
const fsp = tslib_1.__importStar(require("fs/promises"));
const object_hash_1 = tslib_1.__importDefault(require("object-hash"));
const path_1 = tslib_1.__importDefault(require("path"));
class ImageGenerator {
args;
satori;
sharp;
cache = {};
outDir = '';
constructor(args) {
this.args = args;
this.outDir = path_1.default.join(this.args.websiteOutDir, this.args.dir);
}
init = async () => {
this.satori = await import('satori').then((mod) => mod.default);
this.sharp = await import('sharp').then((mod) => mod.default);
if (!fs.existsSync(this.outDir))
await fsp.mkdir(this.outDir, { recursive: true });
};
generate = async (element, options) => {
const hash = (0, object_hash_1.default)([element, options]);
if (this.cache[hash])
return this.cache[hash];
const imageName = `${hash}.png`;
const absolutePath = path_1.default.join(this.outDir, imageName);
const relativePath = path_1.default.join('/', this.args.dir, absolutePath.slice(this.outDir.length));
const svg = await this.satori(element, options);
await this.sharp(Buffer.from(svg)).png().toFile(absolutePath);
const url = new URL(this.args.websiteUrl);
url.pathname = relativePath;
this.cache[hash] = {
relativePath,
absolutePath,
url: url.toString(),
};
return this.cache[hash];
};
}
exports.ImageGenerator = ImageGenerator;
+7
View File
@@ -0,0 +1,7 @@
import { PageData } from '../index';
import { BlogPageData } from './types/blog.types';
import { DocsPageData } from './types/docs.types';
import { ImageRenderer } from './types/image.types';
export declare function imageRendererFactory(plugin: 'docusaurus-plugin-content-docs', handler: ImageRenderer<DocsPageData>): ImageRenderer;
export declare function imageRendererFactory(plugin: 'docusaurus-plugin-content-blog', handler: ImageRenderer<BlogPageData>): ImageRenderer;
export declare function imageRendererFactory(plugin: 'docusaurus-plugin-content-pages', handler: ImageRenderer<PageData>): ImageRenderer;
+7
View File
@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.imageRendererFactory = void 0;
function imageRendererFactory(plugin, handler) {
return handler;
}
exports.imageRendererFactory = imageRendererFactory;
+3
View File
@@ -0,0 +1,3 @@
import { Props } from '@docusaurus/types';
import { PluginOptions } from './types/plugin.types';
export declare const postBuildFactory: (options: PluginOptions) => (props: Props) => Promise<void>;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.postBuildFactory = void 0;
const blog_plugin_1 = require("./blog.plugin");
const docs_plugin_1 = require("./docs.plugin");
const imageGenerator_1 = require("./imageGenerator");
const pages_plugin_1 = require("./pages.plugin");
const plugins = {
[docs_plugin_1.DocsPlugin.plugin]: docs_plugin_1.DocsPlugin,
[blog_plugin_1.BlogPlugin.plugin]: blog_plugin_1.BlogPlugin,
[pages_plugin_1.PagesPlugin.plugin]: pages_plugin_1.PagesPlugin,
};
const postBuildFactory = (options) => async (props) => {
const imageGenerator = new imageGenerator_1.ImageGenerator({
websiteUrl: props.siteConfig.url,
websiteOutDir: props.outDir,
dir: options.path,
});
await imageGenerator.init();
const pluginNames = Object.keys(options.imageRenderers);
for (const pluginName of pluginNames) {
const renderer = options.imageRenderers[pluginName];
const Plugin = plugins[pluginName];
const plugin = Plugin && new Plugin(props, options, imageGenerator, renderer);
plugin && (await plugin.process());
}
};
exports.postBuildFactory = postBuildFactory;
+19
View File
@@ -0,0 +1,19 @@
import { LoadedPlugin, Props } from '@docusaurus/types';
import { PageData } from '../index';
import { ImageGenerator } from './imageGenerator';
import { ImageRenderer } from './types/image.types';
import { PluginOptions } from './types/plugin.types';
export declare class PagesPlugin {
private context;
private options;
private imageGenerator;
private imageRenderer;
static plugin: string;
pages: Omit<PageData, 'document'>[];
constructor(context: Props, options: PluginOptions, imageGenerator: ImageGenerator, imageRenderer: ImageRenderer);
process: () => Promise<void>;
loadData: () => Promise<void>;
loadInstance: (plugin: LoadedPlugin) => Promise<void>;
generate: () => Promise<void>;
getHtmlPath: (permalink: string) => string;
}
+74
View File
@@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PagesPlugin = void 0;
const tslib_1 = require("tslib");
const path = tslib_1.__importStar(require("path"));
const document_1 = require("./document");
class PagesPlugin {
context;
options;
imageGenerator;
imageRenderer;
static plugin = 'docusaurus-plugin-content-pages';
pages = [];
constructor(context, options, imageGenerator, imageRenderer) {
this.context = context;
this.options = options;
this.imageGenerator = imageGenerator;
this.imageRenderer = imageRenderer;
}
process = async () => {
await this.loadData();
await this.generate();
};
loadData = async () => {
const plugins = this.context.plugins.filter((plugin) => plugin.name === PagesPlugin.plugin);
for (const plugin of plugins) {
await this.loadInstance(plugin);
}
};
loadInstance = async (plugin) => {
const content = plugin.content;
const options = plugin.options;
if (!Array.isArray(content))
return;
for (const metadata of content) {
const doc = new document_1.Document(this.getHtmlPath(metadata.permalink));
await doc.load();
const title = (doc.loaded && doc.root.querySelector('title')?.textContent) || '';
const description = (doc.loaded &&
doc.root.querySelector('meta[name=description]')?.textContent) ||
'';
this.pages.push({
metadata: {
...metadata,
title,
description,
},
plugin: options,
});
}
};
generate = async () => {
for (const page of this.pages) {
const document = new document_1.Document(this.getHtmlPath(page.metadata.permalink));
await document.load();
if (!document.loaded)
continue;
const image = await this.imageRenderer({
...page,
document,
websiteOutDir: this.context.outDir,
}, this.context);
if (!image) {
await document.write();
continue;
}
const generated = await this.imageGenerator.generate(...image);
await document.setImage(generated.url);
await document.write();
}
};
getHtmlPath = (permalink) => path.join(this.context.outDir, permalink, 'index.html');
}
exports.PagesPlugin = PagesPlugin;
+27
View File
@@ -0,0 +1,27 @@
import { BlogPaginated, BlogPost, BlogTag, PluginOptions } from '@docusaurus/plugin-content-blog';
import { Document } from '../document';
export type BlogPageType = 'post' | 'list' | 'archive' | 'tags' | 'tag' | 'archive';
export type BlogPageData = {
plugin: PluginOptions;
permalink: string;
document: Document;
} & ({
pageType: Extract<BlogPageType, 'post'>;
data: BlogPost;
} | {
pageType: Extract<BlogPageType, 'list'>;
data: BlogPaginated;
} | {
pageType: Extract<BlogPageType, 'tags'>;
data: {
permalink: string;
};
} | {
pageType: Extract<BlogPageType, 'tag'>;
data: BlogTag['pages'][number]['metadata'] & Pick<BlogTag, 'label'>;
} | {
pageType: Extract<BlogPageType, 'archive'>;
data: {
permalink: string;
};
});
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+9
View File
@@ -0,0 +1,9 @@
/// <reference types="@docusaurus/plugin-content-docs/src/plugin-content-docs.js" />
import { DocMetadata, LoadedVersion, PluginOptions } from '@docusaurus/plugin-content-docs';
import { Document } from '../document';
export type DocsPageData = {
plugin: PluginOptions;
version: LoadedVersion;
metadata: DocMetadata;
document: Document;
};

Some files were not shown because too many files have changed in this diff Show More