feat: types

This commit is contained in:
TrèsAbhi committed 2026-03-19 18:17:36 -05:00
1 parent cef18d4f64
commit c99ed0cb53
11 files changed
+195 -2

No files matched your search

+1
View File
@@ -249,6 +249,7 @@
"winrate",
"wireframe",
"Woah",
"wooorm",
"WOTB",
"wotblitz",
"wotbreplay",
+8
View File
@@ -210,12 +210,14 @@
"@types/react-dom": "^19.2.2",
"@types/three": "^0.180.0",
"@vite-pwa/astro": "^1.1.0",
"@wooorm/starry-night": "^3.9.0",
"astro": "^5.14.4",
"astro-favicons": "^3.1.5",
"autoprefixer": "^10.4.23",
"cssnano": "^7.1.2",
"fuzzysort": "^3.1.0",
"googleapis": "^171.1.0",
"hast-util-to-jsx-runtime": "^2.3.6",
"immer": "^10.1.3",
"lodash-es": "^4.17.21",
"postcss": "^8.5.6",
@@ -1262,6 +1264,8 @@
"@webgpu/types": ["@webgpu/[email protected]", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="],
"@wooorm/starry-night": ["@wooorm/[email protected]", "", { "dependencies": { "@types/hast": "^3.0.0", "import-meta-resolve": "^4.0.0", "vscode-oniguruma": "^2.0.0", "vscode-textmate": "^9.0.0" } }, "sha512-LXVGKfYhTuFhoRuPAHz2XolS/J45L4lI/lCSIBugDpklXYDUPrJyA8tk17u7G32fcFaGODJXH/YDwQDfUXdPRw=="],
"abort-controller": ["[email protected]", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
"acorn": ["[email protected]", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
@@ -2932,6 +2936,10 @@
"vscode-nls": ["[email protected]", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="],
"vscode-oniguruma": ["[email protected]", "", {}, "sha512-poJU8iHIWnC3vgphJnrLZyI3YdqRlR27xzqDmpPXYzA93R4Gk8z7T6oqDzDoHjoikA2aS82crdXFkjELCdJsjQ=="],
"vscode-textmate": ["[email protected]", "", {}, "sha512-n2uGbUcrjhUEBH16uGA0TvUfhWwliFZ1e3+pTjrkim1Mt7ydB41lV08aUvsi70OlzDWp6X7Bx3w/x3fAXIsN0Q=="],
"vscode-uri": ["[email protected]", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
"web-namespaces": ["[email protected]", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
+2
View File
@@ -29,12 +29,14 @@
"@types/react-dom": "^19.2.2",
"@types/three": "^0.180.0",
"@vite-pwa/astro": "^1.1.0",
"@wooorm/starry-night": "^3.9.0",
"astro": "^5.14.4",
"astro-favicons": "^3.1.5",
"autoprefixer": "^10.4.23",
"cssnano": "^7.1.2",
"fuzzysort": "^3.1.0",
"googleapis": "^171.1.0",
"hast-util-to-jsx-runtime": "^2.3.6",
"immer": "^10.1.3",
"lodash-es": "^4.17.21",
"postcss": "^8.5.6",
@@ -1,5 +1,6 @@
---
import ApiMacroSee from "./ApiMacroSee.astro";
import ApiMacroType from "./ApiMacroType.astro";
import { MarkdownCustom } from "./MarkdownCustom";
interface Props {
@@ -54,6 +55,8 @@ for (const line of bodyOriginal.split("\n")) {
<div class="gutter"></div>
<div class="content">
<MarkdownCustom {body} />
{"see" in macros && <ApiMacroSee {locale} value={macros.see} />}
{"type" in macros && <ApiMacroType {locale} value={macros.type} />}
</div>
</div>
@@ -0,0 +1,122 @@
---
import { existsSync } from "fs";
import { readFile } from "fs/promises";
import HighlightedCode from "./HighlightedCode.astro";
import { Link } from "./Link";
interface Props {
value: string;
}
const { value } = Astro.props;
const roots = ["src/protos", "../closed/protos"];
const lang = "proto";
const importPattern = /import "(.+)";/gm;
const messagePattern = /message .+ {\s*\n(.+\s*\n)+}/gm;
const explored = new Set<string>();
let messages: string[] = [];
await pullMessages(`${roots[0]}/${value}.proto`);
async function pullMessages(path: string) {
if (explored.has(path)) return;
explored.add(path);
const file = await readFile(path);
const content = file.toString();
const imports = content.matchAll(importPattern);
for (const _import of imports) {
for (const root of roots) {
const path = `${root}/${_import[1]}`;
if (existsSync(path)) {
await pullMessages(path);
break;
}
}
}
const matchedMessages = content.matchAll(messagePattern);
for (const message of matchedMessages) {
messages = [message[0], ...messages];
}
}
const content = messages.join("\n\n");
const indexPattern = /^( +).+\.(.+ = \d+;)$/m;
let stripped = "";
for (const line of content.split("\n")) {
const matches = line.match(indexPattern);
if (matches === null) {
stripped += `${line}\n`;
continue;
}
stripped += `${matches[1]}${matches[2]}\n`;
}
stripped = stripped.replaceAll(" ", " ");
---
<style>
.types {
overflow: hidden;
position: relative;
&:not([data-expanded="true"]) {
max-height: 16rem;
}
&[data-expanded="true"] {
.overlay {
display: none;
}
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(transparent, var(--gray-1));
display: flex;
align-items: end;
justify-content: center;
}
}
</style>
<script>
const viewers = document.querySelectorAll(".view-full");
for (const viewer of viewers) {
viewer.addEventListener("click", () => {
viewer.parentElement!.parentElement!.dataset.expanded = "true";
});
}
</script>
<div class="types">
<HighlightedCode {lang} content={stripped} />
<div class="overlay">
<Link underline="always" href="#" className="view-full">
View full types
</Link>
</div>
</div>
@@ -1,3 +1,4 @@
.code {
font: inherit;
font-family: var(--font-family-mono);
}
@@ -1,9 +1,9 @@
import type { ComponentProps } from "react";
import { classNames } from "../../core/ui/classNames";
import "./index.css";
import styles from "./index.module.css";
export interface CodeProps extends ComponentProps<"code"> {}
export function Code({ className, ...props }: CodeProps) {
return <code className={classNames("code", className)} {...props} />;
return <code className={classNames(styles.code, className)} {...props} />;
}
@@ -0,0 +1,23 @@
---
import { all, createStarryNight } from "@wooorm/starry-night";
import { HighlightedCodeContent } from "./HighlightedCodeContent";
interface Props {
lang: string;
content: string;
}
const { lang, content } = Astro.props;
const starryNight = await createStarryNight(all);
const scope = starryNight.flagToScope(lang);
if (scope === undefined && lang.length > 0) {
throw new Error(`Unsupported language: ${lang}`);
}
const tree =
lang.length === 0 ? content : starryNight.highlight(content, scope!);
---
<HighlightedCodeContent {tree} />
@@ -0,0 +1,28 @@
import type { Root } from "hast";
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { Code } from "./Code";
interface Props {
tree: Root | string;
}
export function HighlightedCodeContent({ tree }: Props) {
const node =
typeof tree === "string"
? tree
: toJsxRuntime(tree, { Fragment, jsx, jsxs });
return (
<Code
style={{
overflow: "auto",
padding: "var(--space-3)",
display: "block",
whiteSpace: "pre",
lineHeight: "1.5em",
}}
children={node}
/>
);
}
@@ -0,0 +1,3 @@
<style is:global>
@import "@wooorm/starry-night/style/dark";
</style>
@@ -4,6 +4,7 @@ import { getCollection } from "astro:content";
import ApiGroup from "../../../components/ApiGroup.astro";
import { Heading } from "../../../components/Heading";
import { Section } from "../../../components/Section";
import SyntaxStyles from "../../../components/SyntaxStyles.astro";
import ToolBanner from "../../../components/ToolBanner.astro";
import { api } from "../../../core/api/dynamic";
import { tools } from "../../../core/tools/tools";
@@ -25,6 +26,7 @@ paths.sort((a, b) => a.path.localeCompare(b.path));
<BaseLayout {locale} accent="brown">
<ToolBanner {locale} tool={tools.api} slot="pre-app" />
<SyntaxStyles slot="head" />
<Section>
<Heading>{strings.api.json}</Heading>