Skip to content
Closed
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
27 changes: 27 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
contents: read
deployments: write
pull-requests: write
outputs:
deployment-url: ${{ steps.deploy.outputs.deployment-url }}
steps:
- uses: actions/checkout@v6.0.2
- name: Setup Node.js environment
Expand Down Expand Up @@ -76,3 +78,28 @@ jobs:
Deployment Environment: ${{ steps.deploy.outputs.pages-environment }}

${{ steps.deploy.outputs.command-output }}

e2e:
runs-on: ubuntu-latest
name: E2E Tests
needs: deploy
if: ${{ github.actor != 'dependabot[bot]' }}
steps:
- uses: actions/checkout@v6.0.2
- name: Setup Node.js environment
uses: actions/setup-node@v6.3.0
with:
node-version-file: ".node-version"
cache: "yarn"
- name: Enable Corepack
run: corepack enable
- name: Install dependencies
run: yarn install
- name: Build ReScript
run: yarn build:res
- name: Cypress E2E tests
uses: cypress-io/github-action@v7
with:
install: false
browser: chrome
config: baseUrl=${{ needs.deploy.outputs.deployment-url }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ functions/**/*.mjs
functions/**/*.jsx
__tests__/**/*.mjs
__tests__/**/*.jsx
e2e/**/*.mjs
e2e/**/*.jsx
!_shims.mjs
!_shims.jsx

Expand All @@ -72,4 +74,4 @@ _scripts

# Vitest screenshots
!__tests__/__screenshots__/**/*
.vitest-attachments
.vitest-attachments
9 changes: 9 additions & 0 deletions app/routes.res
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ let docsManualRoutes =
->Array.filter(path => !String.includes(path, "docs/manual/api"))
->Array.map(path => route(path, "./routes/DocsManualRoute.jsx", ~options={id: path}))

let docsGuidelinesRoutes =
MdxFile.scanPaths(
~dir="markdown-pages/docs/guidelines",
~alias="docs/guidelines",
)->Array.map(path => route(path, "./routes/DocsGuidelinesRoute.jsx", ~options={id: path}))

let communityRoutes =
MdxFile.scanPaths(~dir="markdown-pages/community", ~alias="community")->Array.map(path =>
route(path, "./routes/CommunityRoute.jsx", ~options={id: path})
Expand All @@ -51,6 +57,8 @@ let mdxRoutes = mdxRoutes("./routes/MdxRoute.jsx")->Array.filter(r =>
String.startsWith(path, "blog/") ||
(path === "docs/manual" || String.startsWith(path, "docs/manual/")) &&
path !== "docs/manual/api" ||
path === "docs/guidelines" ||
String.startsWith(path, "docs/guidelines/") ||
path === "community" ||
String.startsWith(path, "community/")
)
Expand All @@ -74,6 +82,7 @@ let default = [
...beltRoutes,
...blogArticleRoutes,
...docsManualRoutes,
...docsGuidelinesRoutes,
...communityRoutes,
...mdxRoutes,
route("*", "./routes/NotFoundRoute.jsx"),
Expand Down
88 changes: 88 additions & 0 deletions app/routes/DocsGuidelinesRoute.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
type loaderData = {
compiledMdx: CompiledMdx.t,
entries: array<TableOfContents.entry>,
title: string,
description: string,
filePath: string,
}

let loader: ReactRouter.Loader.t<loaderData> = async ({request}) => {
let {pathname} = WebAPI.URL.make(~url=request.url)
let filePath = MdxFile.resolveFilePath(
(pathname :> string),
~dir="markdown-pages/docs/guidelines",
~alias="docs/guidelines",
)

let raw = await Node.Fs.readFile(filePath, "utf-8")
let {frontmatter}: MarkdownParser.result = MarkdownParser.parseSync(raw)

let description = switch frontmatter {
| Object(dict) =>
switch dict->Dict.get("description") {
| Some(String(s)) => s
| _ => ""
}
| _ => ""
}

let title = switch frontmatter {
| Object(dict) =>
switch dict->Dict.get("title") {
| Some(String(s)) => s
| _ => ""
}
| _ => ""
}

let compiledMdx = await MdxFile.compileMdx(raw, ~filePath, ~remarkPlugins=Mdx.plugins)

// Build table of contents entries from markdown headings
let markdownTree = Mdast.fromMarkdown(raw)
let tocResult = Mdast.toc(markdownTree, {maxDepth: 2})

let headers = Dict.make()
Mdast.reduceHeaders(tocResult.map, headers)

let entries =
headers
->Dict.toArray
->Array.map(((header, url)): TableOfContents.entry => {
header,
href: (url :> string),
})
->Array.slice(~start=2) // skip document entry and H1 title, keep h2 sections

{
compiledMdx,
entries,
title: `${title} | ReScript Guidelines`,
description,
filePath,
}
}

let default = () => {
let {compiledMdx, entries, title, description, filePath} = ReactRouter.useLoaderData()

let editHref = `https://github.com/rescript-lang/rescript-lang.org/blob/master/${filePath}`

let categories: array<SidebarLayout.Sidebar.Category.t> = []

<>
<Meta title description />
<NavbarSecondary />
<NavbarTertiary>
<a
href=editHref className="inline text-14 hover:underline text-fire" rel="noopener noreferrer"
>
{React.string("Edit")}
</a>
</NavbarTertiary>
<DocsLayout categories activeToc={title, entries}>
<div className="markdown-body">
<MdxContent compiledMdx />
</div>
</DocsLayout>
</>
}
11 changes: 11 additions & 0 deletions app/routes/DocsGuidelinesRoute.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type loaderData = {
compiledMdx: CompiledMdx.t,
entries: array<TableOfContents.entry>,
title: string,
description: string,
filePath: string,
}

let loader: ReactRouter.Loader.t<loaderData>

let default: unit => React.element
18 changes: 18 additions & 0 deletions cypress.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig } from "cypress";

export default defineConfig({
allowCypressEnv: false,
retries: {
runMode: 2,
openMode: 0,
},
e2e: {
baseUrl: "http://localhost:8080",
specPattern: "e2e/**/*.cy.jsx",
supportFile: "cypress/support/e2e.js",
video: false,
screenshotOnRunFailure: false,
defaultCommandTimeout: 10000,
pageLoadTimeout: 30000,
},
});
23 changes: 23 additions & 0 deletions cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const knownHydrationErrors = [
/Hydration failed because the initial UI does not match what was rendered on the server\.?/,
/Text content does not match server-rendered HTML\.?/,
/There was an error while hydrating\.?/,
/Minified React error #418\b/,
/Minified React error #423\b/,
/Minified React error #425\b/,
];

Cypress.on("uncaught:exception", (err) => {
const message = err && err.message ? err.message : "";
const isKnownHydrationError = knownHydrationErrors.some((pattern) =>
pattern.test(message),
);

if (isKnownHydrationError) {
console.warn("Suppressing known React hydration exception in Cypress:", {
message,
error: err,
});
return false;
}
});
8 changes: 4 additions & 4 deletions data/api/v13.0.0/stdlib.json
Original file line number Diff line number Diff line change
Expand Up @@ -2427,9 +2427,9 @@
"kind": "value",
"name": "compare",
"docstrings": [
"`compare(collator, a, b)` compares two strings using the rules of `collator`. Returns a negative number when `a` comes before `b`, `0` when equal, and a positive number otherwise.\n\n## Examples\n\n```rescript\nlet collator = Intl.Collator.make(~locales=[\"en-US\"])\ncollator->Intl.Collator.compare(\"apple\", \"banana\") < 0\n```"
"`compare(collator, a, b)` compares two strings using the rules of `collator`. Returns a negative number when `a` comes before `b`, `0` when equal, and a positive number otherwise.\n\n## Examples\n\n```rescript\nlet collator = Intl.Collator.make(~locales=[\"en-US\"])\nOrdering.isLess(collator->Intl.Collator.compare(\"apple\", \"banana\"))\n```"
],
"signature": "let compare: (t, string, string) => int"
"signature": "let compare: (t, string, string) => Ordering.t"
},
{
"id": "Stdlib.Intl.Collator.ignore",
Expand Down Expand Up @@ -5984,9 +5984,9 @@
"kind": "value",
"name": "localeCompare",
"docstrings": [
"`localeCompare(referenceStr, compareStr)` returns a float than indicatings\nwhether a reference string comes before or after, or is the same as the given\nstring in sort order. If `referenceStr` occurs before `compareStr` positive if\nthe `referenceStr` occurs after `compareStr`, `0` if they are equivalent.\nDo not rely on exact return values of `-1` or `1`\nSee [`String.localeCompare`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) on MDN.\n\n## Examples\n\n```rescript\nString.localeCompare(\"a\", \"c\") < 0.0 == true\nString.localeCompare(\"a\", \"a\") == 0.0\n```"
"`localeCompare(referenceStr, compareStr, ~locales=?, ~options=?)` returns a float indicating\nwhether a reference string comes before or after, or is the same as the given\nstring in sort order. Returns a negative value if `referenceStr` occurs before `compareStr`,\npositive if `referenceStr` occurs after `compareStr`, `0` if they are equivalent.\nDo not rely on exact return values of `-1` or `1`.\n\nOptionally takes `~locales` to specify locale(s) and `~options` to customize comparison behavior\n(e.g., sensitivity, case ordering, numeric sorting). These correspond to the `Intl.Collator` options.\nSee [`String.localeCompare`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) on MDN.\n\n## Examples\n\n```rescript\nString.localeCompare(\"a\", \"c\") < 0.0 == true\nString.localeCompare(\"a\", \"a\") == 0.0\nString.localeCompare(\"a\", \"b\", ~locales=[\"en-US\"]) < 0.0 == true\nString.localeCompare(\"a\", \"A\", ~locales=[\"en-US\"], ~options={sensitivity: #base}) == 0.0\n```"
],
"signature": "let localeCompare: (string, string) => float"
"signature": "let localeCompare: (\n string,\n string,\n ~locales: array<string>=?,\n ~options: Intl_Collator.options=?,\n) => float"
},
{
"id": "Stdlib.String.ignore",
Expand Down
Loading