forked from langchain-ai/langchainjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement custom webpack loader for example code blocks & implement c…
…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
Showing
3 changed files
with
123 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} /> | ||
</> | ||
); | ||
} |