Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ jobs:
cache: yarn
- name: Install dependencies
run: yarn
- name: Check generated route types
run: |
yarn check:routes
git diff --exit-code -- packages/shared/src/Path.res
- name: Test examples and hrefs
run: yarn test
# Confirms that Wrangler can start the Docs Pages and Guide local dev servers.
Expand Down
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ apps/guide/src/**/*.mjs
apps/guide/src/**/*.jsx
packages/*/src/**/*.mjs
packages/*/src/**/*.jsx
apps/docs/scripts/gendocs.mjs
apps/docs/scripts/generate_*.mjs
apps/docs/scripts/gendocs.jsx
apps/docs/scripts/generate_*.jsx
apps/docs/scripts/LogAlgoliaEnvStatus.jsx
apps/docs/scripts/__tests__/**/*.jsx
Expand Down
5 changes: 1 addition & 4 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"apps/docs/app/**/*.mjs",
"build",
"data/api/**/*.json",
"apps/docs/data/api/**/*.json",
"dist",
"apps/docs/index_data/*.json",
"node_modules/",
Expand All @@ -32,13 +31,11 @@
"apps/docs/lib/",
".vercel",
"apps/docs/src/**/*.mjs",
"apps/docs/scripts/gendocs.mjs",
"apps/docs/scripts/generate_*.mjs",
"apps/docs/public/llms/manual/**/llm*.txt",
"apps/docs/public/llms/react/**/llm*.txt",
"apps/docs/markdown-pages/docs/**/**/llms.mdx",
"apps/docs/markdown-pages/docs/manual/installation.mdx",
".yarn/releases/yarn-4.12.0.cjs",
"apps/docs/data/api/*"
".yarn/releases/yarn-4.12.0.cjs"
]
}
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ Tailwind is configured in [`styles/main.css`](styles/main.css). There is no `tai
| `yarn dev` | Prepare generated files and run the local development environment |
| `yarn build` | Run the full production build |
| `yarn preview` | Build and serve the generated static client locally |
| `yarn build:res` | Compile ReScript only |
| `yarn build:res` | Generate route types and compile ReScript |
| `yarn build:routes` | Regenerate the shared ReScript route type |
| `yarn check:routes` | Check that the shared route type matches the current routes |
| `yarn dev:res` | Run the ReScript compiler in watch mode |
| `yarn format` | Run Prettier and the ReScript formatter |
| `yarn test` | Run markdown example and href validation |
Expand All @@ -102,6 +104,13 @@ Tailwind is configured in [`styles/main.css`](styles/main.css). There is no `tai

## Testing

The documentation route table lives in `apps/docs/route-config.mjs`. React Router
and `apps/docs/generate-route-types.mjs` read the same configuration, including
MDX pages and API modules. `packages/shared/src/Path.res` is generated before
ReScript builds and when starting the ReScript watcher. After changing routes,
adding or removing MDX pages, or updating API data during a watch session, run
`yarn build:routes` again. CI rejects a stale generated file.

### Vitest Browser Tests

We use [Vitest](https://vitest.dev/) in browser mode with Playwright for component-level tests. Test files live in `__tests__/` and are written in ReScript.
Expand Down
113 changes: 0 additions & 113 deletions apps/docs/app/DocsRoutes.res

This file was deleted.

14 changes: 0 additions & 14 deletions apps/docs/app/DocsRoutes.resi

This file was deleted.

4 changes: 3 additions & 1 deletion apps/docs/app/routes.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export { default } from "./DocsRoutes.jsx";
import { loadRoutes } from "../route-config.mjs";

export default loadRoutes().routes;
48 changes: 4 additions & 44 deletions apps/docs/app/routes/ApiDocs.res
Original file line number Diff line number Diff line change
Expand Up @@ -336,45 +336,11 @@ let make = (props: props) => {
<SidebarPageLayout sidebar rightSidebar docSearchLvl0="API"> children </SidebarPageLayout>
}

module Data = {
type t = {
mainModule: Dict.t<JSON.t>,
tree: Dict.t<JSON.t>,
}

let dir = try {
Node.Path.resolve("data", "api")
} catch {
| _ => ""
}

let getVersion = (~moduleName: string) => {
open Node

let moduleContent =
Fs.readFileSync(`markdown-pages/docs/api/${moduleName}.json`)->JSON.parseOrThrow

let content = switch moduleContent {
| Object(dict) => dict->Some
| _ => None
}

switch content {
| Some(content) => Some({mainModule: content, tree: Dict.make()})
| _ => None
}
}
}

let processStaticProps = (~slug: array<string>) => {
let moduleName = slug->Belt.Array.getExn(0)
let processStaticProps = (~apiDocs, ~slug: array<string>) => {
let moduleName = slug->Array.at(0)->Option.getOrThrow
let modulePath = slug->Array.join("/")

let content =
// TODO post RR7: rename this to getByModuleName
Data.getVersion(~moduleName)
->Option.map(data => data.mainModule)
->Option.flatMap(Dict.get(_, modulePath))
let content = Dict.get(apiDocs, modulePath)

switch content {
| Some(json) =>
Expand Down Expand Up @@ -456,14 +422,8 @@ let processStaticProps = (~slug: array<string>) => {
items: sortedItems,
}

Ok({module_, toctree: Obj.magic({name: "root", path: [], children: []})})
Ok({module_, toctree: {name: "root", path: [], children: []}})

| None => Error(`Failed to get API Data for module ${moduleName}`)
}
}

let getStaticProps = async slug => {
let result = processStaticProps(~slug)

{"props": result}
}
61 changes: 26 additions & 35 deletions apps/docs/app/routes/ApiRoute.res
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
type loaderData = ApiDocs.props

type rec apiItem = {
id: string,
kind: string,
name: string,
items?: array<apiItem>,
docStrings: array<string>,
let stringField = (fields, key) => {
switch Dict.get(fields, key) {
| Some(JSON.String(value)) => value
| _ => JsError.throwWithMessage(`Invalid API item: missing ${key}`)
}
}

let rec rawApiItemToNode = (apiItem: apiItem): ApiDocs.node => {
let rec rawApiItemToNode = (json: JSON.t): ApiDocs.node => {
let fields = switch json {
| Object(fields) => fields
| _ => JsError.throwWithMessage("Invalid API item: expected an object")
}
let items = switch Dict.get(fields, "items") {
| Some(Array(items)) => items
| _ => []
}
{
name: apiItem.name,
path: apiItem.id
name: stringField(fields, "name"),
path: stringField(fields, "id")
->String.split(".")
->Array.filter(segment =>
segment !== "Stdlib" && segment !== "Belt" && segment !== "Js" && segment !== "Dom"
),
children: apiItem.items
->Option.map(items =>
Array.filter(items, item =>
item.id
->String.split(".")
->Array.length > 3
)->Array.map(rawApiItemToNode)
children: items
->Array.filter(item =>
switch item {
| Object(fields) => stringField(fields, "id")->String.split(".")->Array.length > 3
| _ => false
}
)
->Option.getOr([]),
->Array.map(rawApiItemToNode),
}
}

@scope("JSON") @val
external parseApi: string => Dict.t<apiItem> = "parse"

let groupItems = apiDocs => {
let parsedItems =
apiDocs
Expand Down Expand Up @@ -130,25 +133,13 @@ let loader: ReactRouter.Loader.t<loaderData> = async args => {

let basePath = path[0]->Option.getUnsafe

let apiDocs = switch basePath {
| "belt" => parseApi(await Node.Fs.readFile("./markdown-pages/docs/api/belt.json", "utf-8"))
| "dom" => parseApi(await Node.Fs.readFile("./markdown-pages/docs/api/dom.json", "utf-8"))
| _ => parseApi(await Node.Fs.readFile("./markdown-pages/docs/api/stdlib.json", "utf-8"))
}
let apiDocs = ApiData.current()->ApiData.library(basePath)

let toctree = groupItems(apiDocs)

let data = {
// TODO POST RR7: refactor this function to only return the module and not the toctree
// or move the toc logic to this function
try {
await ApiDocs.getStaticProps(path)
} catch {
| err => {"props": Error(JSON.stringifyAny(err)->Option.getOr("Error loading API data"))}
}
}
let data = ApiDocs.processStaticProps(~apiDocs, ~slug=path)

data["props"]->Result.map((item): ApiDocs.api => {
data->Result.map((item): ApiDocs.api => {
{
module_: item.module_,
toctree: {
Expand Down
10 changes: 1 addition & 9 deletions apps/docs/app/routes/ApiRoute.resi
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
type loaderData = ApiDocs.props

type rec apiItem = {
id: string,
kind: string,
name: string,
items?: array<apiItem>,
docStrings: array<string>,
}

/** Loads API documentation after normalizing React Router data-request pathnames. */
/** Loads page content and navigation from the same published compiler dataset. */
let loader: ReactRouter.Loader.t<loaderData>

let default: unit => React.element
Loading
Loading