From a2dbeeb6c76244f7af086a7cfc5fb6d77c73cca7 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 21 Nov 2024 10:19:20 +0100 Subject: [PATCH 1/7] Initial starlight plugin setup --- astro.config.mjs | 28 ++++++++++++++++++++++++++++ docs/apidocs/meh.astro | 11 +++++++++++ 2 files changed, 39 insertions(+) create mode 100644 docs/apidocs/meh.astro diff --git a/astro.config.mjs b/astro.config.mjs index 38237d2..f4cae70 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,6 +2,33 @@ import { readFileSync } from "node:fs"; import { defineConfig } from "astro/config"; import starlight from "@astrojs/starlight"; +const starlightPlugin = { + name: "RescriptAPIDocs", + hooks: { + setup: ({ config, updateConfig, addIntegration }) => { + console.log(`Setup yow!`) + addIntegration({ + name: "RescriptAPIDocs", + hooks: { + "astro:config:setup": ({ injectRoute }) => { + injectRoute({ + pattern: "meh", + entrypoint: "docs/apidocs/meh.astro" + }) + } + } + }) + + updateConfig({ + sidebar: [ + ...config.sidebar, + { label: "meh", link: "meh" } + ] + }); + } + } +} + const rescriptTM = JSON.parse( readFileSync("./docs/assets/rescript.tmLanguage.json", "utf-8"), ); @@ -44,6 +71,7 @@ export default defineConfig({ langs: [rescriptTM], }, }, + plugins: [starlightPlugin], }), ], }); diff --git a/docs/apidocs/meh.astro b/docs/apidocs/meh.astro new file mode 100644 index 0000000..1591aa7 --- /dev/null +++ b/docs/apidocs/meh.astro @@ -0,0 +1,11 @@ +--- +import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; + +const frontmatter = { + title: "Meh", +} +--- + + +

Muhahah

+
From 3c74fe8a73aa6dc504fe541fb0ea55fc07b972c2 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 21 Nov 2024 16:47:25 +0100 Subject: [PATCH 2/7] Very rough generation of API documentation --- .prettierrc.mjs | 13 ++++++++ astro.config.mjs | 60 ++++++++++++++-------------------- docs/apidocs/meh.astro | 11 ------- docs/pages/apidocs/[API].astro | 38 +++++++++++++++++++++ docs/pages/apidocs/index.astro | 31 ++++++++++++++++++ docs/pages/apidocs/utils.js | 47 ++++++++++++++++++++++++++ package-lock.json | 52 ++++++++++++++++++++++++++--- package.json | 5 +-- src/DOMAPI/Window.js | 4 +-- 9 files changed, 207 insertions(+), 54 deletions(-) create mode 100644 .prettierrc.mjs delete mode 100644 docs/apidocs/meh.astro create mode 100644 docs/pages/apidocs/[API].astro create mode 100644 docs/pages/apidocs/index.astro create mode 100644 docs/pages/apidocs/utils.js diff --git a/.prettierrc.mjs b/.prettierrc.mjs new file mode 100644 index 0000000..4f88aa5 --- /dev/null +++ b/.prettierrc.mjs @@ -0,0 +1,13 @@ +/** @type {import("prettier").Config} */ +export default { + plugins: ["prettier-plugin-astro"], + overrides: [ + { + files: "*.astro", + options: { + parser: "astro", + }, + }, + ], + endOfLine: "lf", + }; \ No newline at end of file diff --git a/astro.config.mjs b/astro.config.mjs index f4cae70..00f8ec7 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,38 +1,17 @@ import { readFileSync } from "node:fs"; import { defineConfig } from "astro/config"; import starlight from "@astrojs/starlight"; - -const starlightPlugin = { - name: "RescriptAPIDocs", - hooks: { - setup: ({ config, updateConfig, addIntegration }) => { - console.log(`Setup yow!`) - addIntegration({ - name: "RescriptAPIDocs", - hooks: { - "astro:config:setup": ({ injectRoute }) => { - injectRoute({ - pattern: "meh", - entrypoint: "docs/apidocs/meh.astro" - }) - } - } - }) - - updateConfig({ - sidebar: [ - ...config.sidebar, - { label: "meh", link: "meh" } - ] - }); - } - } -} +import { apiModules } from "./docs/pages/apidocs/utils"; const rescriptTM = JSON.parse( readFileSync("./docs/assets/rescript.tmLanguage.json", "utf-8"), ); +const apiSidebarItems = apiModules.map(({ moduleName, link }) => ({ + label: moduleName, + link, +})); + export default defineConfig({ srcDir: "docs", publicDir: "docs/public", @@ -45,24 +24,36 @@ export default defineConfig({ src: "./docs/assets/rescript-logo.svg", }, social: { - github: 'https://github.com/rescript-lang/experimental-rescript-webapi', + github: "https://github.com/rescript-lang/experimental-rescript-webapi", }, editLink: { - baseUrl: 'https://github.com/rescript-lang/experimental-rescript-webapi/edit/main/', + baseUrl: + "https://github.com/rescript-lang/experimental-rescript-webapi/edit/main/", }, sidebar: [ { - slug: '', + slug: "", + }, + { + slug: "design-philosophy", }, { - slug: 'design-philosophy', + slug: "project-status", }, { - slug: 'project-status', + label: "Contributing", + autogenerate: { directory: "contributing" }, }, { - label: 'Contributing', - autogenerate: { directory: 'contributing' }, + label: "API Documentation", + collapsed: true, + items: [ + { + label: "Overview", + link: "apidocs", + }, + ...apiSidebarItems, + ], }, ], customCss: ["./docs/styles/fonts.css", "./docs/styles/theme.css"], @@ -71,7 +62,6 @@ export default defineConfig({ langs: [rescriptTM], }, }, - plugins: [starlightPlugin], }), ], }); diff --git a/docs/apidocs/meh.astro b/docs/apidocs/meh.astro deleted file mode 100644 index 1591aa7..0000000 --- a/docs/apidocs/meh.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; - -const frontmatter = { - title: "Meh", -} ---- - - -

Muhahah

-
diff --git a/docs/pages/apidocs/[API].astro b/docs/pages/apidocs/[API].astro new file mode 100644 index 0000000..54097ca --- /dev/null +++ b/docs/pages/apidocs/[API].astro @@ -0,0 +1,38 @@ +--- +import { apiModules, getDoc } from "./utils"; +import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; + +export async function getStaticPaths() { + return apiModules.map((apiModule) => { + return { + params: { + API: apiModule.apiRoute, + }, + props: apiModule, + }; + }); +} + +const { moduleName, filePath } = Astro.props; + +const frontmatter = { + title: moduleName, +}; + +const headings = [ + // { + // depth: 2, + // slug: "web-apis", + // text: "Web APIs", + // }, +]; + +const docInfo = await getDoc(filePath); +--- + + +

{moduleName} overview

+ +
{JSON.stringify(docInfo, null, 4)}
+
+
diff --git a/docs/pages/apidocs/index.astro b/docs/pages/apidocs/index.astro new file mode 100644 index 0000000..3ffc820 --- /dev/null +++ b/docs/pages/apidocs/index.astro @@ -0,0 +1,31 @@ +--- +import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; +import { apiModules } from "./utils"; + +const frontmatter = { + title: "API Documentation", +}; + +const headings = [ + { + depth: 2, + slug: "web-apis", + text: "Web APIs", + }, +]; + +const resFiles = apiModules; +--- + + +

Web APIs

+
    + { + resFiles.map(({ moduleName, link }) => ( +
  • + {moduleName} +
  • + )) + } +
+
diff --git a/docs/pages/apidocs/utils.js b/docs/pages/apidocs/utils.js new file mode 100644 index 0000000..bf4e628 --- /dev/null +++ b/docs/pages/apidocs/utils.js @@ -0,0 +1,47 @@ +import * as path from "node:path"; +import { exec } from "node:child_process"; +import { promisify } from "node:util"; + +const execAsync = promisify(exec); + +function toKebabCase(input) { + return input + .replace(/([a-z])([A-Z])/g, "$1-$2") // Insert dash between lowercase and uppercase + .replace(/[\s_]+/g, "-") // Replace spaces or underscores with dash + .toLowerCase(); // Convert to lowercase +} + +function mapRescriptFile(file) { + const moduleName = path + .basename(file, ".res") + .replace("$", "") + .replace("API", " API"); + const link = `apidocs/${toKebabCase(moduleName)}`; + return { + filePath: path.join(import.meta.dirname, file), + moduleName, + link, + apiRoute: toKebabCase(moduleName), + }; +} + +export const apiModules = Object.keys( + import.meta.glob("../../../src/*.res"), +).map(mapRescriptFile); + +export const fileModules = Object.keys( + import.meta.glob("../../../src/**/*.res"), +).map(mapRescriptFile); + +export async function getDoc(absoluteFilePath) { + const { stdout, stderr } = await execAsync( + `rescript-tools doc ${absoluteFilePath}`, + { + maxBuffer: 1024 * 1024 * 10, // Increase buffer to 10 MB + }, + ); + if (stderr) { + throw new Error(stderr); + } + return JSON.parse(stdout); +} diff --git a/package-lock.json b/package-lock.json index 6f220d2..455f3d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,13 @@ "version": "0.1.0", "license": "MIT", "dependencies": { - "rescript": "^12.0.0-alpha.4" + "rescript": "^12.0.0-alpha.5" }, "devDependencies": { "@astrojs/starlight": "^0.29.0", "astro": "^4.16.10", "prettier": "^3.3.3", + "prettier-plugin-astro": "^0.14.1", "sharp": "^0.33.5" } }, @@ -5880,6 +5881,21 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-plugin-astro": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz", + "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@astrojs/compiler": "^2.9.1", + "prettier": "^3.0.0", + "sass-formatter": "^0.7.6" + }, + "engines": { + "node": "^14.15.0 || >=16.0.0" + } + }, "node_modules/prismjs": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", @@ -6253,15 +6269,16 @@ } }, "node_modules/rescript": { - "version": "12.0.0-alpha.4", - "resolved": "https://registry.npmjs.org/rescript/-/rescript-12.0.0-alpha.4.tgz", - "integrity": "sha512-w9uIv8C8+kBWbcb1GVn1rOdLEj2YX1TIRvUkR6DSvVO8oSdJ0GAUABN7y7WU/+zCkjNwsVrBlO0hG7NTJqXHUA==", + "version": "12.0.0-alpha.5", + "resolved": "https://registry.npmjs.org/rescript/-/rescript-12.0.0-alpha.5.tgz", + "integrity": "sha512-s2GGg9fkoiDBiP0uuJ1RRG5NBq+SkGqxMEmt32q9tTJoueL7bfU/9Jj3UgSwFFNdehuns1taAOvP2DV4IE+R9A==", "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", "bin": { "bsc": "cli/bsc", "bstracing": "lib/bstracing", "rescript": "cli/rescript", + "rescript-tools": "cli/rescript-tools", "rewatch": "cli/rewatch" }, "engines": { @@ -6423,6 +6440,23 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/s.color": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/s.color/-/s.color-0.0.15.tgz", + "integrity": "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass-formatter": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/sass-formatter/-/sass-formatter-0.7.9.tgz", + "integrity": "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "suf-log": "^2.5.3" + } + }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", @@ -6705,6 +6739,16 @@ "inline-style-parser": "0.2.4" } }, + "node_modules/suf-log": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/suf-log/-/suf-log-2.5.3.tgz", + "integrity": "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==", + "dev": true, + "license": "MIT", + "dependencies": { + "s.color": "0.0.15" + } + }, "node_modules/tinyexec": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", diff --git a/package.json b/package.json index bbbd3ee..a59c0fb 100644 --- a/package.json +++ b/package.json @@ -29,18 +29,19 @@ "scripts": { "test": "node tests/index.js", "build": "rewatch", - "format": "rescript format -all && prettier --write ./tests/index.js ./package.json", + "format": "rescript format -all && prettier --write ./tests/index.js ./package.json ./docs/pages", "docs": "astro dev", "build:docs": "astro build" }, "license": "MIT", "dependencies": { - "rescript": "^12.0.0-alpha.4" + "rescript": "^12.0.0-alpha.5" }, "devDependencies": { "@astrojs/starlight": "^0.29.0", "astro": "^4.16.10", "prettier": "^3.3.3", + "prettier-plugin-astro": "^0.14.1", "sharp": "^0.33.5" } } diff --git a/src/DOMAPI/Window.js b/src/DOMAPI/Window.js index 977be07..dbf8d92 100644 --- a/src/DOMAPI/Window.js +++ b/src/DOMAPI/Window.js @@ -1,7 +1,7 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -import * as EventTarget$WebApi from "../EventAPI/EventTarget.js"; +import * as EventTarget$WebAPI from "../EventAPI/EventTarget.js"; -EventTarget$WebApi.Impl({}); +EventTarget$WebAPI.Impl({}); /* Not a pure module */ From 6430d271ec624d260abd2b8bff6d6f53f96d667c Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 22 Nov 2024 09:12:31 +0100 Subject: [PATCH 3/7] Render types with documentation and signature --- docs/pages/apidocs/[API].astro | 60 +++++++++++++++++++++++++++------- docs/styles/theme.css | 2 +- package-lock.json | 7 ++-- package.json | 1 + 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/docs/pages/apidocs/[API].astro b/docs/pages/apidocs/[API].astro index 54097ca..7a4a8fe 100644 --- a/docs/pages/apidocs/[API].astro +++ b/docs/pages/apidocs/[API].astro @@ -1,6 +1,8 @@ --- import { apiModules, getDoc } from "./utils"; import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; +import { Code } from "@astrojs/starlight/components"; +import { micromark } from "micromark"; export async function getStaticPaths() { return apiModules.map((apiModule) => { @@ -15,24 +17,60 @@ export async function getStaticPaths() { const { moduleName, filePath } = Astro.props; +const docInfo = await getDoc(filePath); + +const types = docInfo.items + .filter((item) => item.kind === "type") + .sort((a, b) => a.name.localeCompare(b.name)) + .map((type) => { + const documentation = + type.docstrings && micromark(type.docstrings.join("\n")); + return { + name: type.name, + documentation, + signature: type.signature, + }; + }); + +const typeHeadings = types.map((type) => ({ + depth: 3, + slug: type.name, + text: type.name, +})); + const frontmatter = { title: moduleName, }; const headings = [ - // { - // depth: 2, - // slug: "web-apis", - // text: "Web APIs", - // }, + { + depth: 2, + slug: "types", + text: "Types", + }, + ...typeHeadings, ]; - -const docInfo = await getDoc(filePath); --- -

{moduleName} overview

- -
{JSON.stringify(docInfo, null, 4)}
-
+
+

Types

+ { + types.map((type) => ( +
+

{type.name}

+
+ +
+ )) + } + +
{JSON.stringify(docInfo, null, 4)}
+
+
+ diff --git a/docs/styles/theme.css b/docs/styles/theme.css index cc9f342..f793165 100644 --- a/docs/styles/theme.css +++ b/docs/styles/theme.css @@ -21,7 +21,7 @@ https://github.com/rescript-lang/rescript-lang.org/blob/4e4f9520f6fc7a0376db82a0 } } -body { +body, #starlight__sidebar { --scrollbar-track-background: #222222; --scrollbar-track-border: #4a4a4a; --scrollbar-thumb-background: #686868; diff --git a/package-lock.json b/package-lock.json index 455f3d9..cc11b2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "devDependencies": { "@astrojs/starlight": "^0.29.0", "astro": "^4.16.10", + "micromark": "^4.0.1", "prettier": "^3.3.3", "prettier-plugin-astro": "^0.14.1", "sharp": "^0.33.5" @@ -4620,9 +4621,9 @@ } }, "node_modules/micromark": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", - "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", + "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index a59c0fb..93f2b77 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "devDependencies": { "@astrojs/starlight": "^0.29.0", "astro": "^4.16.10", + "micromark": "^4.0.1", "prettier": "^3.3.3", "prettier-plugin-astro": "^0.14.1", "sharp": "^0.33.5" From 0bf7964ae31a80cefe99f44f1e37a0447087eb14 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 22 Nov 2024 12:00:43 +0100 Subject: [PATCH 4/7] Add record fields --- docs/components/record.astro | 48 ++++++++++++++++++++++++++++++++++ docs/pages/apidocs/[API].astro | 15 +++++++++++ docs/styles/theme.css | 6 +++++ 3 files changed, 69 insertions(+) create mode 100644 docs/components/record.astro diff --git a/docs/components/record.astro b/docs/components/record.astro new file mode 100644 index 0000000..9e0f00b --- /dev/null +++ b/docs/components/record.astro @@ -0,0 +1,48 @@ +--- +import { micromark } from "micromark"; +const { name, items, typesInOwnModule } = Astro.props; +--- + +

Record fields

+{ + items.map((item) => { + const documentation = + item.docstrings && micromark(item.docstrings.join("\n")); + + return ( +
+
{item.name}
+
+ {typesInOwnModule.has(item.signature) ? ( + {item.signature} + ) : ( + item.signature + )} +
+ {documentation &&
} +
+ ); + }) +} + + diff --git a/docs/pages/apidocs/[API].astro b/docs/pages/apidocs/[API].astro index 7a4a8fe..7d7ba0d 100644 --- a/docs/pages/apidocs/[API].astro +++ b/docs/pages/apidocs/[API].astro @@ -3,6 +3,7 @@ import { apiModules, getDoc } from "./utils"; import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; import { Code } from "@astrojs/starlight/components"; import { micromark } from "micromark"; +import Record from "../../components/record.astro"; export async function getStaticPaths() { return apiModules.map((apiModule) => { @@ -15,6 +16,10 @@ export async function getStaticPaths() { }); } +function showRecord(details) { + return details && details.kind === "record" && details.items.length > 0; +} + const { moduleName, filePath } = Astro.props; const docInfo = await getDoc(filePath); @@ -29,9 +34,12 @@ const types = docInfo.items name: type.name, documentation, signature: type.signature, + detail: type.detail, }; }); +const typesInOwnModule = new Set(types.map((t) => t.name)); + const typeHeadings = types.map((type) => ({ depth: 3, slug: type.name, @@ -61,6 +69,13 @@ const headings = [

{type.name}

+ {showRecord(type.detail) ? ( + + ) : null}
)) } diff --git a/docs/styles/theme.css b/docs/styles/theme.css index f793165..e122932 100644 --- a/docs/styles/theme.css +++ b/docs/styles/theme.css @@ -8,6 +8,12 @@ https://github.com/withastro/starlight/blob/main/packages/starlight/style/props. https://github.com/rescript-lang/rescript-lang.org/blob/4e4f9520f6fc7a0376db82a0a6db52211e8a8187/tailwind.config.mjs#L13 */ +@media (prefers-reduced-motion: no-preference) { + html { + scroll-behavior: smooth; /* Enables smooth scrolling for users without motion sensitivity */ + } +} + :root[data-theme="light"], [data-theme="light"] ::backdrop { --sl-color-accent-low: #4a0f14; From 26d40882379be451710400d3e6f2ea39649010ef Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 22 Nov 2024 13:42:03 +0100 Subject: [PATCH 5/7] Process signatures and have links between types in modules. --- docs/components/record.astro | 11 ++++--- docs/components/signature.astro | 49 +++++++++++++++++++++++++++++ docs/components/signatureItem.astro | 29 +++++++++++++++++ docs/pages/apidocs/[API].astro | 3 -- docs/pages/apidocs/utils.js | 6 +++- 5 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 docs/components/signature.astro create mode 100644 docs/components/signatureItem.astro diff --git a/docs/components/record.astro b/docs/components/record.astro index 9e0f00b..1db4096 100644 --- a/docs/components/record.astro +++ b/docs/components/record.astro @@ -1,5 +1,6 @@ --- import { micromark } from "micromark"; +import Signature from "./signature.astro"; const { name, items, typesInOwnModule } = Astro.props; --- @@ -13,11 +14,10 @@ const { name, items, typesInOwnModule } = Astro.props;
{item.name}
- {typesInOwnModule.has(item.signature) ? ( - {item.signature} - ) : ( - item.signature - )} +
{documentation &&
}
@@ -37,6 +37,7 @@ const { name, items, typesInOwnModule } = Astro.props; & .type { justify-self: end; color: var(--sl-color-accent-low); + margin-top: 0; } & .doc { diff --git a/docs/components/signature.astro b/docs/components/signature.astro new file mode 100644 index 0000000..43ab542 --- /dev/null +++ b/docs/components/signature.astro @@ -0,0 +1,49 @@ +--- +import SignatureItem from "./signatureItem.astro"; + + +function tokenize(input) { + // Split by special characters while keeping them + const regex = /([<>,])/g; + return input + .split(regex) + .map((token) => token.trim()) + .filter(Boolean); +} + +function parseTokens(tokens) { + let index = 0; + + const parseNode = () => { + const ident = tokens[index++]; // Read the current token and increment index + let genericArguments = []; + + if (tokens[index] === "<") { + // Check for generics + index++; // Consume "<" + while (tokens[index] !== ">") { + genericArguments.push(parseNode()); + if (tokens[index] === ",") index++; // Consume "," + } + index++; // Consume ">" + } + + return { ident, genericArguments }; + }; + + return parseNode(); +} + +function parse(input) { + const tokens = tokenize(input); + return parseTokens(tokens); +} + + +const { signature, typesInOwnModule } = Astro.props; +const tree = parse(signature); +--- + +
+ {()} +
diff --git a/docs/components/signatureItem.astro b/docs/components/signatureItem.astro new file mode 100644 index 0000000..f33b0b3 --- /dev/null +++ b/docs/components/signatureItem.astro @@ -0,0 +1,29 @@ +--- +import { createModuleLink } from "../pages/apidocs/utils.js"; +const { item, typesInOwnModule } = Astro.props; + +let link; +if (typesInOwnModule.has(item.ident)) { + link = `#${item.ident}`; +} + +if (item.ident.startsWith("WebAPI.")) { + const idents = item.ident.split("."); + if (idents.length === 3){ + link = `${createModuleLink(idents[1])}#${idents[2]}`; + } +} +--- + +{link ? {item.ident} : item.ident} +{ + item.genericArguments.length > 0 && ( + <> + {"<"} + {item.genericArguments.map((subItem) => ( + + ))} + {">"} + + ) +} diff --git a/docs/pages/apidocs/[API].astro b/docs/pages/apidocs/[API].astro index 7d7ba0d..6b07d72 100644 --- a/docs/pages/apidocs/[API].astro +++ b/docs/pages/apidocs/[API].astro @@ -79,9 +79,6 @@ const headings = [
)) } - -
{JSON.stringify(docInfo, null, 4)}
-
diff --git a/docs/components/value.astro b/docs/components/value.astro new file mode 100644 index 0000000..66e9faa --- /dev/null +++ b/docs/components/value.astro @@ -0,0 +1,27 @@ +--- +import SignatureItem from "./signatureItem.astro"; +const { parameters, returnType } = Astro.props; +--- + +
+

Parameters

+ { + parameters.map((p) => ( + + )) + } +

Return type

+ +
+ diff --git a/docs/pages/apidocs/[API].astro b/docs/pages/apidocs/[API].astro index c150d6e..aa8d9b7 100644 --- a/docs/pages/apidocs/[API].astro +++ b/docs/pages/apidocs/[API].astro @@ -1,5 +1,7 @@ --- -import { apiModules, getDoc } from "./utils"; +import * as path from "node:path"; +import { existsSync } from "fs"; +import { apiModules, getDoc, createTypeModuleLink } from "../../utils"; import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; import { Code } from "@astrojs/starlight/components"; import { micromark } from "micromark"; @@ -20,7 +22,17 @@ function showRecord(details) { return details && details.kind === "record" && details.items.length > 0; } -const { moduleName, filePath } = Astro.props; +function getModuleFileName(typeName) { + return `${typeName[0].toUpperCase()}${typeName.slice(1)}`; +} + +function showModule(typeName, filePath) { + const moduleFileName = `${getModuleFileName(typeName)}.res`; + const potentialPath = path.join(filePath.replace(".res", ""), moduleFileName); + return existsSync(potentialPath); +} + +const { moduleName, filePath, link } = Astro.props; const docInfo = await getDoc(filePath); @@ -76,6 +88,20 @@ const headings = [ {...type.detail} /> ) : null} + {showModule(type.name, filePath) && ( + <> +

Module

+

+ There are methods and helpers defined in{" "} + + {getModuleFileName(type.name)} + + . +

+ + )}
)) } diff --git a/docs/pages/apidocs/[API]/[Module].astro b/docs/pages/apidocs/[API]/[Module].astro index ad71fcb..e6a5590 100644 --- a/docs/pages/apidocs/[API]/[Module].astro +++ b/docs/pages/apidocs/[API]/[Module].astro @@ -1,9 +1,9 @@ --- -import { apiModules, getDoc } from "../utils"; -// import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; -// import { Code } from "@astrojs/starlight/components"; -// import { micromark } from "micromark"; -// import Record from "../../components/record.astro"; +import { apiModules, getDoc } from "../../../utils"; +import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; +import { Code } from "@astrojs/starlight/components"; +import { micromark } from "micromark"; +import Value from "../../../components/value.astro"; export async function getStaticPaths() { return apiModules.flatMap((apiModule) => { @@ -19,7 +19,68 @@ export async function getStaticPaths() { }); } -const name = Astro.props.currentModule.moduleName; +function showValue(detail) { + return ( + detail?.kind === "signature" && detail?.details?.parameters?.length > 0 + ); +} + +const { filePath, moduleName } = Astro.props.currentModule; +const docInfo = await getDoc(filePath); + +const values = docInfo.items + .filter((item) => item.kind === "value") + .sort((a, b) => a.name.localeCompare(b.name)) + .map((value) => { + const documentation = + value.docstrings && micromark(value.docstrings.join("\n")); + return { + name: value.name, + documentation, + signature: value.signature, + detail: value.detail, + }; + }); + +const valueHeadings = values.map((value) => ({ + depth: 3, + slug: value.name, + text: value.name, +})); + +const frontmatter = { + title: moduleName, +}; + +const headings = [ + { + depth: 2, + slug: "values", + text: "Values", + }, + ...valueHeadings, +]; --- -

Yupla {name}

+ +

Values

+ { + values.map((value) => ( +
+

{value.name}

+
+ + {showValue(value.detail) && } +
+ )) + } +
+{JSON.stringify(docInfo, null, 4)}
+
+ + diff --git a/docs/pages/apidocs/index.astro b/docs/pages/apidocs/index.astro index 3ffc820..f2bfe5d 100644 --- a/docs/pages/apidocs/index.astro +++ b/docs/pages/apidocs/index.astro @@ -1,6 +1,6 @@ --- import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; -import { apiModules } from "./utils"; +import { apiModules } from "../../utils"; const frontmatter = { title: "API Documentation", @@ -14,14 +14,13 @@ const headings = [ }, ]; -const resFiles = apiModules; ---

Web APIs

    { - resFiles.map(({ moduleName, link }) => ( + apiModules.map(({ moduleName, link }) => (
  • {moduleName}
  • diff --git a/docs/pages/apidocs/utils.js b/docs/utils.js similarity index 65% rename from docs/pages/apidocs/utils.js rename to docs/utils.js index f615cd6..a34e781 100644 --- a/docs/pages/apidocs/utils.js +++ b/docs/utils.js @@ -12,8 +12,14 @@ function toKebabCase(input) { .toLowerCase(); // Convert to lowercase } -export function createModuleLink(moduleName) { - return `/apidocs/${toKebabCase(moduleName)}`; +export function createAPIModuleLink(moduleName) { + // This function is called before import.meta.env.BASE_URL is set. + // So, I'm hardcoding the path here. + return `apidocs/${toKebabCase(moduleName)}`; +} + +export function createTypeModuleLink(parentModuleLink, typeName) { + return `${parentModuleLink}/${toKebabCase(typeName)}`; } function mapTypeModules(parentModuleLink, file) { @@ -27,20 +33,20 @@ function mapTypeModules(parentModuleLink, file) { return files .filter((f) => f.endsWith(".res")) .map((file) => { - const fullPath = path.join(folder, file); + const filePath = path.join(folder, file); const moduleName = file .replace("$", "") .replace(folder, "") .replace(".res", ""); const apiRouteParameter = toKebabCase(moduleName); - const link = `${parentModuleLink}/${apiRouteParameter}`; + const link = createTypeModuleLink(parentModuleLink, moduleName); const typeName = moduleName[0].toLocaleLowerCase() + moduleName.slice(1); return [ typeName, { - fullPath, + filePath, moduleName, link, apiRouteParameter, @@ -49,13 +55,10 @@ function mapTypeModules(parentModuleLink, file) { }); } -function mapRescriptFile(file) { - const moduleName = path - .basename(file, ".res") - .replace("$", "") - .replace("API", " API"); - const filePath = path.join(import.meta.dirname, file); - const link = createModuleLink(moduleName); +function mapRescriptFile(srcDir, file) { + const moduleName = path.basename(file, ".res").replace("$", ""); + const filePath = path.join(srcDir, file); + const link = createAPIModuleLink(moduleName); const items = Object.fromEntries(mapTypeModules(link, filePath)); return { @@ -67,13 +70,8 @@ function mapRescriptFile(file) { }; } -export const apiModules = Object.keys( - import.meta.glob("../../../src/*.res"), -).map(mapRescriptFile); - -export const fileModules = Object.keys( - import.meta.glob("../../../src/**/*.res"), -).map(mapRescriptFile); +const srcDir = path.resolve(process.cwd(), "src"); +export const apiModules = readdirSync(srcDir).filter(f => f.endsWith(".res")).map(r => mapRescriptFile(srcDir, r)); export async function getDoc(absoluteFilePath) { const { stdout, stderr } = await execAsync(