Fix: More examples / snippets fixes + rework (#2150)

* feat: start reworking snippets

* feat: start cleaning up gen script

* fix: start updating refs everywhere

* feat: start fixing broken snippet links

* fix: more snippets

* fix: more updates

* chore: lint

* fix: taskfile

* fix: script

* fix: escaping issue + mergent blog

* fix: bunch more

* chore: lint

* fix: implement more of them

* fix: retry

* fix: the rest

* chore: lint

* fix: highlight

* fix: ugh

* fix: start removing dead code from old snippet method

* fix: rest of the refs

* fix: remove all of the rest of the <GithubSnippet uses

* fix: couple more

* fix: last few errors

* fix: handle example writes

* fix: delete to test update

* fix: CI, attempt 1

* feat: helpful error on no snippet

* fix: lint

* chore: rm unused js file

* feat: improve GHA

* debug: run action on branch

* fix: rm pnpm

* fix: try to leave comment instead

* fix: don't run on branch

* fix: factor out GH info

* fix: include code path

* fix: ts
This commit is contained in:
matt
2025-08-17 10:22:16 -05:00
committed by GitHub
parent d8dd0c9cbb
commit f8e5f357d9
100 changed files with 1115 additions and 6613 deletions
+45 -28
View File
@@ -1,6 +1,5 @@
import React from "react";
import { parseDocComments } from "./codeParser";
import { Src } from "./codeData";
import CodeStyleRender from "./CodeStyleRender";
import { Button } from "../ui/button";
import {
@@ -11,6 +10,13 @@ import {
UnfoldVertical,
} from "lucide-react";
type Src = {
raw: string;
codePath?: string;
githubUrl?: string;
language?: string;
};
interface CodeRendererProps {
source: Src;
target?: string;
@@ -23,27 +29,28 @@ export const CodeBlock = ({ source, target }: CodeRendererProps) => {
const parsed = parseDocComments(source.raw, target, collapsed);
const canCollapse = source.raw.includes("// ...") || source.raw.includes("# ...")
const canCollapse =
source.raw.includes("// ...") || source.raw.includes("# ...");
return (
<>
<div className="z-10 bg-background flex flex-row gap-4 justify-between items-center pl-2 mb-2">
<div className="flex flex-row gap-2">
{source.githubUrl && (
{source.githubUrl && (
<a
href={source.githubUrl}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-gray-500 font-mono hover:underline"
>
{source.props?.path}
</a>
)}
>
{source.codePath}
</a>
)}
</div>
<div className="flex gap-2 justify-end">
{canCollapse && (
<Button
variant="ghost"
{canCollapse && (
<Button
variant="ghost"
size="sm"
onClick={() => setCollapsed(!collapsed)}
>
@@ -58,11 +65,11 @@ export const CodeBlock = ({ source, target }: CodeRendererProps) => {
Collapse
</>
)}
</Button>
)}
<Button
variant="outline"
size="sm"
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={() => {
navigator.clipboard.writeText(parsed);
setCopied(true);
@@ -101,20 +108,30 @@ export const CodeBlock = ({ source, target }: CodeRendererProps) => {
<div className="flex flex-row mt-2 justify-between">
<div className="flex gap-4">
{source.githubUrl && <a href={source.githubUrl} target="_blank" rel="noopener noreferrer">
<Button variant="outline" size="sm" className="flex flex-row gap-2">
<svg
height="16"
width="16"
viewBox="0 0 16 16"
fill="currentColor"
{source.githubUrl && (
<a
href={source.githubUrl}
target="_blank"
rel="noopener noreferrer"
>
<Button
variant="outline"
size="sm"
className="flex flex-row gap-2"
>
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
View Full Code Example on GitHub{" "}
<MoveUpRight className="w-3 h-3" />
</Button>
</a>}
<svg
height="16"
width="16"
viewBox="0 0 16 16"
fill="currentColor"
>
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
</svg>
View Full Code Example on GitHub{" "}
<MoveUpRight className="w-3 h-3" />
</Button>
</a>
)}
</div>
<div className="flex gap-4">
<Button
@@ -1,28 +0,0 @@
import React from "react";
import { useData } from "nextra/hooks";
import { CodeBlock } from "./CodeBlock";
import { RepoProps, Src } from "./codeData";
interface GithubSnippetProps {
src: RepoProps;
target: string;
}
export const GithubSnippet = ({ src, target }: GithubSnippetProps) => {
const { contents } = useData();
const snippet = contents.find((c) => c.rawUrl.endsWith(src.path)) as Src;
if (!snippet) {
return null;
}
return (
<CodeBlock
source={{
...src,
...snippet,
}}
target={target}
/>
);
};
+30 -53
View File
@@ -1,62 +1,39 @@
import React, { useMemo } from "react";
import React from "react";
import { CodeBlock } from "./CodeBlock";
import { Snippet as SnippetType } from "@/lib/snips";
import { type Snippet as SnippetType } from "@/lib/snippet";
interface SnippetProps {
src: SnippetType;
block?: keyof SnippetType["blocks"] | "ALL";
}
type Language = SnippetType["language"];
const languageMap = {
typescript: "ts",
python: "py",
go: "go",
unknown: "txt",
// See the list of supported languages for how to define these:
// https://highlightjs.readthedocs.io/en/latest/supported-languages.html
const languageToHighlightAbbreviation = (language: Language) => {
switch (language) {
case "python":
return "py";
case "typescript":
return "ts";
case "go":
return "go";
default:
const exhaustiveCheck: never = language;
throw new Error(`Unsupported language: ${exhaustiveCheck}`);
}
};
// This is a server component that will be rendered at build time
export const Snippet = ({ src, block }: SnippetProps) => {
if (!src.content) {
throw new Error(`src content is required: ${src.source}`);
export const Snippet = ({ src }: { src: SnippetType }) => {
if (src === undefined) {
throw new Error(
"Snippet was undefined. You probably provided a path to a snippet that doesn't exist."
);
}
const language = useMemo(() => {
const normalizedLanguage = src.language?.toLowerCase().trim();
if (normalizedLanguage && normalizedLanguage in languageMap) {
return languageMap[normalizedLanguage as keyof typeof languageMap];
}
return "txt";
}, [src.language]);
let content = src.content;
if (block && block !== "ALL" && src.blocks) {
if (!(block in src.blocks)) {
throw new Error(
`Block ${block} not found in ${src.source} ${JSON.stringify(src.blocks, null, 2)}`
);
}
const lines = src.content.split("\n");
content = lines
.slice(src.blocks[block].start - 1, src.blocks[block].stop)
.join("\n");
}
const fixedSource = src.source.replace("out/", "examples/");
return (
<>
<CodeBlock
source={{
githubUrl: `https://github.com/hatchet-dev/hatchet/blob/main/${fixedSource}`,
raw: content || "",
language: language,
props: {
path: fixedSource,
},
}}
/>
</>
<CodeBlock
source={{
githubUrl: src.githubUrl,
raw: src.content,
language: languageToHighlightAbbreviation(src.language),
codePath: src.codePath,
}}
/>
);
};
@@ -1,99 +0,0 @@
const defaultUser = "hatchet-dev";
const defaultRepo = "hatchet";
const localPaths: Record<string, string> = {
ts: "sdks/typescript",
py: "sdks/python",
go: "",
};
export const extToLanguage: Record<string, string> = {
ts: "typescript",
py: "python",
go: "go",
};
const defaultBranch = "main";
export type RepoProps = {
user?: string;
repo?: string;
branch?: string;
path?: string;
};
const getLocalUrl = (ext: string | undefined, { path }: RepoProps) => {
if (!ext) return `http://localhost:4001/${path}`;
return `http://localhost:4001/${localPaths[ext] || ''}/${path}`;
};
const isDev = process?.env?.NODE_ENV === "development";
const getRawUrl = ({ user, repo, branch, path }: RepoProps) => {
const ext = path?.split(".").pop();
if (isDev) {
return getLocalUrl(ext, { path });
}
const extPath = ext && localPaths[ext] ? `${localPaths[ext]}/` : '';
return `https://raw.githubusercontent.com/${user || defaultUser}/${repo || defaultRepo}/refs/heads/${branch || defaultBranch}/${extPath}${path}`;
};
const getUIUrl = ({ user, repo, branch, path }: RepoProps) => {
const ext = path?.split(".").pop();
if (isDev) {
return getLocalUrl(ext, { path });
}
const extPath = ext && localPaths[ext] ? `${localPaths[ext]}/` : '';
return `https://github.com/${user || defaultUser}/${repo || defaultRepo}/blob/${branch || defaultBranch}/${extPath}${path}`;
};
export type Src = {
raw: string;
props?: RepoProps;
rawUrl?: string;
githubUrl?: string;
language?: string;
};
export const getSnippets = (
props: RepoProps[]
): Promise<{ props: { ssg: { contents: Src[] } } }> => {
return Promise.all(
props.map(async (prop) => {
const rawUrl = getRawUrl(prop);
const githubUrl = getUIUrl(prop);
const fileExt = prop.path?.split(".").pop() as keyof typeof extToLanguage;
const language = extToLanguage[fileExt];
try {
const response = await fetch(rawUrl);
const raw = await response.text();
return {
raw,
props: prop,
rawUrl,
githubUrl,
language,
};
} catch (error) {
// Return object with empty raw content but preserve URLs on failure
return {
raw: "",
props: prop,
rawUrl,
githubUrl,
language,
};
}
})
).then((results) => ({
props: {
ssg: {
contents: results,
},
// revalidate every 60 seconds
revalidate: 60,
},
}));
};
+3 -5
View File
@@ -1,5 +1,3 @@
export * from './GithubSnippet'
export * from './Snippet'
export * from './CodeBlock'
export * from './codeData'
export * from './codeParser'
export * from "./Snippet";
export * from "./CodeBlock";
export * from "./codeParser";