From 366afb58bd272bcd13e514147e25a8c5c811931e Mon Sep 17 00:00:00 2001 From: Taras Mankovski Date: Sun, 29 Sep 2024 12:58:13 -0400 Subject: [PATCH] Output JSDoc for functions --- www/components/api.tsx | 25 +++++++++++ www/components/exports.tsx | 42 +++++++++++++++++++ www/components/package-exports.tsx | 61 --------------------------- www/hooks/use-package.tsx | 66 +++++++++++++++++++++++------- www/routes/package.tsx | 6 ++- 5 files changed, 122 insertions(+), 78 deletions(-) create mode 100644 www/components/api.tsx create mode 100644 www/components/exports.tsx delete mode 100644 www/components/package-exports.tsx diff --git a/www/components/api.tsx b/www/components/api.tsx new file mode 100644 index 0000000..bde9f04 --- /dev/null +++ b/www/components/api.tsx @@ -0,0 +1,25 @@ +import type { JSXElement } from "revolution"; +import type { Package } from "../hooks/use-package.tsx"; + +interface DescriptionProps { + pkg: Package +} + +export function API({ pkg }: DescriptionProps): JSXElement { + return ( + <> + {Object.keys(pkg.docs).flatMap((exportName) => { + const nodes = pkg.docs[exportName]; + return nodes.map(node => { + const { MDXDoc = () => <> } = node + return ( + <> +

{node.name}

+ + + ) + }) + })} + + ); +} \ No newline at end of file diff --git a/www/components/exports.tsx b/www/components/exports.tsx new file mode 100644 index 0000000..7819788 --- /dev/null +++ b/www/components/exports.tsx @@ -0,0 +1,42 @@ +import { join } from "jsr:@std/path@1.0.6"; +import type { JSXElement } from "revolution/jsx-runtime"; + +import type { DocNode } from "../hooks/use-deno-doc.tsx"; +import { DEFAULT_MODULE_KEY, RenderableDocNode, type Package } from "../hooks/use-package.tsx"; + +export function Exports({ pkg }: { pkg: Package }): JSXElement { + return ( + <> + {Object.keys(pkg.docs).map((exportName) => ( + + ))} + + ); +} + +interface PackageExportOptions { + packageName: string; + exportName: string; + doc: Array; +} + +function PackageExport({ packageName, exportName, doc }: PackageExportOptions) { + const exports = doc.flatMap((doc) => { + if (doc.declarationKind === "export") { + return [ + {doc.name}, ", "]; + } else { + return []; + } + }).slice(0, -1); + + return ( +
+      import {{" "}<>{exports}{" "}} from "{join(packageName, exportName)}"
+    
+ ); +} \ No newline at end of file diff --git a/www/components/package-exports.tsx b/www/components/package-exports.tsx deleted file mode 100644 index 98ed49f..0000000 --- a/www/components/package-exports.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { join } from "jsr:@std/path@1.0.6"; -import type { JSXElement } from "revolution/jsx-runtime"; - -import type { DocNode } from "../hooks/use-deno-doc.tsx"; -import type { Package } from "../hooks/use-package.tsx"; - -export function PackageExports({ pkg }: { pkg: Package }): JSXElement { - if (isDocArray(pkg.docs)) { - if (typeof pkg.exports === "string") { - return ( - - ); - } - } else { - const doc = pkg.docs; - return ( - <> - {Object.keys(pkg.docs).map((exportName) => ( - - ))} - - ); - } - return <> -} - -interface PackageExportOptions { - packageName: string; - exportName: string; - doc: Array; -} - -function PackageExport({ packageName, exportName, doc }: PackageExportOptions) { - const exports = doc.flatMap((doc) => { - if (doc.declarationKind === "export") { - return [doc.name]; - } else { - return []; - } - }); - return ( - - import { {exports.join(", ")}{" "} - } from "{join(packageName, exportName)}" - - ); -} - -function isDocArray( - doc: Array | Record>, -): doc is Array { - return Array.isArray(doc); -} diff --git a/www/hooks/use-package.tsx b/www/hooks/use-package.tsx index f03fbc0..a4e865c 100644 --- a/www/hooks/use-package.tsx +++ b/www/hooks/use-package.tsx @@ -1,7 +1,8 @@ -import { call, type Operation } from "effection"; +import { all, call, type Operation } from "effection"; import { join, resolve } from "jsr:@std/path@1.0.6"; import type { VFile } from "npm:vfile@6.0.3"; import { z } from "npm:zod@3.23.8"; +import type { JSXElement } from "revolution"; import { PrivatePackageError } from "../errors.ts"; import { type DocNode, useDenoDoc } from "./use-deno-doc.tsx"; @@ -13,12 +14,17 @@ export interface Package { workspace: string; packageName: string; readme: string; - exports: string | Record; - docs: Array | Record>; + exports: Record; + docs: Record>; MDXContent: () => JSX.Element; MDXDescription: () => JSX.Element; } +export type RenderableDocNode = DocNode & { + id: string; + MDXDoc?: () => JSXElement; +}; + const DenoJson = z.object({ name: z.string(), version: z.optional(z.string()), @@ -26,6 +32,8 @@ const DenoJson = z.object({ private: z.union([z.undefined(), z.literal(true)]), }); +export const DEFAULT_MODULE_KEY = "."; + export function* usePackage(workspace: string): Operation { const workspacePath = resolve( import.meta.dirname ?? "", @@ -52,28 +60,56 @@ export function* usePackage(workspace: string): Operation { let file: VFile = yield* useRemarkParse(readme); - let docs: Package["docs"]; - if (typeof denoJson.exports === "string") { - docs = yield* useDenoDoc( - `${new URL(join(workspacePath, denoJson.exports), "file://")}`, - ); - } else { - docs = {}; - for (const key of Object.keys(denoJson.exports)) { - docs[key] = yield* useDenoDoc( - `${new URL(join(workspacePath, denoJson.exports[key]), "file://")}`, - ); + const exports = typeof denoJson.exports === "string" + ? { + [DEFAULT_MODULE_KEY]: denoJson.exports, } + : denoJson.exports; + + const entrypoints: Record = {}; + for (const key of Object.keys(exports)) { + entrypoints[key] = new URL(join(workspacePath, exports[key]), "file://"); + } + + let docs: Package["docs"] = {}; + for (const key of Object.keys(entrypoints)) { + const docNodes = yield* useDenoDoc(String(entrypoints[key])); + docs[key] = yield* all(docNodes.map(function* (node) { + if (node.jsDoc && node.jsDoc.doc) { + try { + const mod = yield* useMDX(node.jsDoc.doc); + return { + id: exportHash(key, node), + ...node, + MDXDoc: () => mod.default({}) + }; + } catch (e) { + console.error(`Could not parse doc string for ${node.name} at ${node.location}`, e) + } + } + return { + id: exportHash(key, node), + ...node + }; + })); } return { workspace: workspace.replace("./", ""), path: workspacePath, packageName: denoJson.name, - exports: denoJson.exports, + exports, readme, docs, MDXContent: () => content, MDXDescription: () => <>{file.data?.meta?.description}, }; } + +function exportHash(exportName: string, doc: DocNode): string { + if (exportName === DEFAULT_MODULE_KEY) { + return doc.name + } else { + return `${exportName}__${doc.name}`; + } +} \ No newline at end of file diff --git a/www/routes/package.tsx b/www/routes/package.tsx index e23c08b..7a60c23 100644 --- a/www/routes/package.tsx +++ b/www/routes/package.tsx @@ -4,7 +4,8 @@ import { useAppHtml } from "./app.html.tsx"; import type { Package } from "../hooks/use-package.tsx"; import type { RoutePath, SitemapRoute } from "effection-www/plugins/sitemap.ts"; import { usePackages } from "../hooks/use-packages.ts"; -import { PackageExports } from "../components/package-exports.tsx"; +import { Exports } from "../components/exports.tsx"; +import { API } from "../components/api.tsx"; export function packageRoute(): SitemapRoute { return { @@ -56,7 +57,8 @@ export function packageRoute(): SitemapRoute {

- + + );