diff --git a/src/components/GitHubCode.astro b/src/components/GitHubCode.astro new file mode 100644 index 000000000000000..2f3a56e34898082 --- /dev/null +++ b/src/components/GitHubCode.astro @@ -0,0 +1,68 @@ +--- +import { z } from "astro:schema"; +import { Code } from "@astrojs/starlight/components"; + +type Props = z.infer; + +const props = z + .object({ + repo: z.string(), + commit: z.string(), + file: z.string(), + lang: z.string(), + lines: z + .string() + .transform((val) => val.split("-").map(Number)) + .optional(), + tag: z.string().optional(), + }) + .refine( + (val) => { + return !(val.lines && val.tag); + }, + { message: "Lines and tag are mutually exclusive filters." }, + ); + +const { repo, commit, file, lang, lines, tag } = props.parse(Astro.props); + +const res = await fetch( + `https://gh-code.developers.cloudflare.com/${repo}/${commit}/${file}`, +); + +if (!res.ok) { + throw new Error(`[GitHubCode] Received ${res.status} from Worker.`); +} + +let content = await res.text(); + +if (lines) { + const [start, end] = lines; + + const contentLines = content.split("\n"); + + if (contentLines.length < end - 1) { + throw new Error( + `[GitHubCode] End line requested is beyond content length (${contentLines.length}).`, + ); + } + + content = contentLines.slice(start - 1, end).join("\n"); +} else if (tag) { + const contentLines = content.split("\n"); + + const startTag = contentLines.findIndex((x) => + x.includes(``), + ); + const endTag = contentLines.findIndex((x) => + x.includes(``), + ); + + if (!startTag || !endTag) { + throw new Error(`[GitHubCode] Unable to find a region using tag "${tag}".`); + } + + content = contentLines.slice(startTag + 1, endTag).join("\n"); +} +--- + + diff --git a/src/components/index.ts b/src/components/index.ts index 457ab88c88bb506..6af42ac464dbf21 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -16,6 +16,7 @@ export { default as ExternalResources } from "./ExternalResources.astro"; export { default as Feature } from "./Feature.astro"; export { default as FeatureTable } from "./FeatureTable.astro"; export { default as Flex } from "./Flex.astro"; +export { default as GitHubCode } from "./GitHubCode.astro"; export { default as Glossary } from "./Glossary.astro"; export { default as GlossaryDefinition } from "./GlossaryDefinition.astro"; export { default as GlossaryTooltip } from "./GlossaryTooltip.astro"; @@ -51,7 +52,7 @@ export { default as ThreeCardGrid } from "./ThreeCardGrid.astro"; export { default as TroubleshootingList } from "./TroubleshootingList.astro"; export { default as TunnelCalculator } from "./TunnelCalculator.astro"; export { default as Type } from "./Type.astro"; -export { default as TypeScriptExample } from "./TypeScriptExample.astro" +export { default as TypeScriptExample } from "./TypeScriptExample.astro"; export { default as WorkersArchitectureDiagram } from "./WorkersArchitectureDiagram.astro"; export { default as WorkersIsolateDiagram } from "./WorkersIsolateDiagram.astro"; export { default as WorkerStarter } from "./WorkerStarter.astro"; diff --git a/src/content/docs/style-guide/components/github-code.mdx b/src/content/docs/style-guide/components/github-code.mdx new file mode 100644 index 000000000000000..ca038adab5fb40f --- /dev/null +++ b/src/content/docs/style-guide/components/github-code.mdx @@ -0,0 +1,124 @@ +--- +title: GitHubCode +--- + +The `GitHubCode` component allows you to include files from Cloudflare repositories. + +The remote content can be filtered by lines or a region enclosed in tags. + +## Import + +```mdx +import { GitHubCode } from "~/components"; +``` + +## Usage + +```mdx live +import { GitHubCode } from "~/components"; + + +``` + +### Filtering by lines + +```mdx +import { GitHubCode } from "~/components"; + +{/* +import { foo } from "bar"; + +const baz = foo(); + +console.log(baz); +*/} + +{/* +import { foo } from "bar"; + +const baz = foo(); +*/} +``` + +### Filtering by tag + +```mdx +import { GitHubCode } from "~/components"; + +{/* + +import { foo } from "bar"; + +const baz = foo(); + + +console.log(baz); +*/} + +{/* +import { foo } from "bar"; + +const baz = foo(); +*/} +``` + +## `` Props + +### `repo` + +**required** +**type:** `string` + +The owner and repository to pull from, for example `cloudflare/workers-rs`. + +### `file` + +**required** +**type:** `string` + +The file path to pull from, for example `templates/hello-world/src/lib.rs`. + +### `commit` + +**required** +**type:** `string` + +The long (40-characters) Git commit hash to pull from, for example `ab3951b5c95329a600a7baa9f9bb1a7a95f1aeaa`. + +### `lang` + +**required** +**type:** `string` + +The language to use for the code block, for example `rs`. + +### `lines` + +**type:** `string` + +A range of lines to filter the content using, for example `1-3`. + +### `tag` + +**type:** `string` + +A region to filter the content with, for example `no-logging`. + +This should be represented as starting `` and closing `` comments in the source file. \ No newline at end of file