Skip to content

Commit

Permalink
Implement custom webpack loader for example code blocks & implement c…
Browse files Browse the repository at this point in the history
…ustom CodeBlock component

- Loader lists all langchain objects used in the example, and finds the path to its reference docs
- CodeBlock component renders a card containing links to the reference doc of each
  • Loading branch information
nfcampos committed Apr 18, 2023
1 parent 90d6740 commit f0fa40a
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
75 changes: 75 additions & 0 deletions docs/code-block-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* eslint-disable prefer-template */
/* eslint-disable no-param-reassign */
// eslint-disable-next-line import/no-extraneous-dependencies
const babel = require("@babel/core");
const path = require("path");
const fs = require("fs");

/**
*
* @param {string|Buffer} content Content of the resource file
* @param {object} [map] SourceMap data consumable by https://github.com/mozilla/source-map
* @param {any} [meta] Meta data, could be anything
*/
async function webpackLoader(content, map, meta) {
const cb = this.async();

if (!this.resourcePath.endsWith(".ts")) {
cb(null, JSON.stringify({ content, imports: [] }), map, meta);
return;
}

try {
const result = await babel.parseAsync(content, {
sourceType: "module",
filename: this.resourcePath,
});

const imports = [];

result.program.body.forEach((node) => {
if (node.type === "ImportDeclaration") {
const source = node.source.value;

if (!source.startsWith("langchain")) {
return;
}

node.specifiers.forEach((specifier) => {
if (specifier.type === "ImportSpecifier") {
const local = specifier.local.name;
imports.push({ local, source });
} else {
throw new Error("Unsupported import type");
}
});
}
});

imports.forEach((imported) => {
const { local, source } = imported;
const moduleName = source.split("/").slice(1).join("_");
const docsPath = path.resolve(__dirname, "docs", "api", moduleName);
const available = fs.readdirSync(docsPath, { withFileTypes: true });
const found = available.find(
(dirent) =>
dirent.isDirectory() &&
fs.existsSync(path.resolve(docsPath, dirent.name, local + ".md"))
);
if (found) {
imported.docs =
"/" + path.join("docs", "api", moduleName, found.name, local);
} else {
throw new Error(
`Could not find docs for ${source}.${local} in docs/api/`
);
}
});

cb(null, JSON.stringify({ content, imports }), map, meta);
} catch (err) {
cb(err);
}
}

module.exports = webpackLoader;
5 changes: 1 addition & 4 deletions docs/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ const config = {
"docusaurus-plugin-typedoc",
{
tsconfig: "../langchain/tsconfig.json",
sidebar: {
fullNames: true,
},
},
],
() => ({
Expand All @@ -56,7 +53,7 @@ const config = {
rules: [
{
test: examplesPath,
use: "raw-loader",
use: ["json-loader", "./code-block-loader.js"],
},
{
test: /\.m?js/,
Expand Down
47 changes: 47 additions & 0 deletions docs/src/theme/CodeBlock/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable react/jsx-props-no-spreading */
import React from "react";
import CodeBlock from "@theme-original/CodeBlock";

function Imports({ imports }) {
return (
<div
style={{
paddingTop: "0.85rem",
background: "var(--prism-background-color)",
color: "var(--prism-color)",
marginTop: "calc(-1 * var(--ifm-leading))",
marginBottom: "var(--ifm-leading)",
boxShadow: "var(--ifm-global-shadow-lw)",
borderBottomLeftRadius: "var(--ifm-code-border-radius)",
borderBottomRightRadius: "var(--ifm-code-border-radius)",
}}
>
<h4 style={{ paddingLeft: "0.65rem", marginBottom: "0.45rem" }}>
Reference Docs:
</h4>
<ul style={{ paddingBottom: "1rem" }}>
{imports.map(({ local, source, docs }) => (
<li>
<a href={docs}>
<span>{local}</span>
</a>{" "}
from <code>{source}</code>
</li>
))}
</ul>
</div>
);
}

export default function CodeBlockWrapper({ children, ...props }) {
if (typeof children === "string") {
return <CodeBlock {...props}>{children}</CodeBlock>;
}

return (
<>
<CodeBlock {...props}>{children.content}</CodeBlock>
<Imports imports={children.imports} />
</>
);
}

0 comments on commit f0fa40a

Please sign in to comment.