diff --git a/apps/control-panel/src/components/experiments/experiment-results-comparison.test.tsx b/apps/control-panel/src/components/experiments/experiment-results-comparison.test.tsx
index 8009acbd..d14b7bac 100644
--- a/apps/control-panel/src/components/experiments/experiment-results-comparison.test.tsx
+++ b/apps/control-panel/src/components/experiments/experiment-results-comparison.test.tsx
@@ -227,13 +227,13 @@ describe("ExperimentResultsComparison ordering and states", () => {
expect(text).toContain("Confidence interval unavailable");
});
- it("does not format estimates or differences without the Metric type", () => {
+ it("does not format estimates or differences when the Metric is missing from the catalog", () => {
const text = visibleText(
renderToStaticMarkup(
,
diff --git a/apps/control-panel/src/components/experiments/experiment-results-panel.tsx b/apps/control-panel/src/components/experiments/experiment-results-panel.tsx
index c78ceb10..4cb28591 100644
--- a/apps/control-panel/src/components/experiments/experiment-results-panel.tsx
+++ b/apps/control-panel/src/components/experiments/experiment-results-panel.tsx
@@ -7,7 +7,6 @@ const ExperimentConclusionDialog = lazy(() =>
})),
);
-import type { Metric } from "@splitch/contracts";
import type { PanelExperimentRun } from "@splitch/control-plane-sdk/panel-experiments";
import { useSuspenseQuery } from "@tanstack/react-query";
import {
@@ -16,6 +15,7 @@ import {
ExperimentResultsWaiting,
} from "#components/experiments/experiment-results";
import { experimentResultsQuery } from "#lib/experiments/experiments-query";
+import type { ComparisonMetric } from "#lib/experiments/metric-comparison-rows";
/**
* Route-facing wrapper: resolves the Run to read, then renders it.
@@ -43,7 +43,7 @@ export function ExperimentResultsPanel({
flagId: string;
environmentId: string;
experimentId: string;
- metrics: readonly Pick[];
+ metrics: readonly ComparisonMetric[];
run: PanelExperimentRun | undefined;
}) {
if (!run) return ;
@@ -77,7 +77,7 @@ function ExperimentResultsForRun({
flagId: string;
environmentId: string;
experimentId: string;
- metrics: readonly Pick[];
+ metrics: readonly ComparisonMetric[];
run: PanelExperimentRun;
}) {
const [concluding, setConcluding] = useState(false);
diff --git a/apps/control-panel/src/components/experiments/experiment-results-test-fixtures.ts b/apps/control-panel/src/components/experiments/experiment-results-test-fixtures.ts
index a503b851..4aa8ea57 100644
--- a/apps/control-panel/src/components/experiments/experiment-results-test-fixtures.ts
+++ b/apps/control-panel/src/components/experiments/experiment-results-test-fixtures.ts
@@ -9,6 +9,7 @@ import type {
PanelExperimentResultsReady,
PanelExperimentRun,
} from "@splitch/control-plane-sdk/panel-experiments";
+import type { ComparisonMetric } from "#lib/experiments/metric-comparison-rows";
/**
* Panel fixtures built the way the Worker builds the payload: the gate is
@@ -251,10 +252,10 @@ export function resultsNoDataFixture(
}
/** Catalog rows for the Metric ids the stats fixtures use, as the detail read returns them. */
-export function metricsFixture(): { id: string; name: string }[] {
+export function metricsFixture(): ComparisonMetric[] {
return [
- { id: "checkout_conversion", name: "Checkout conversion" },
- { id: "checkout_latency_p95", name: "Checkout latency p95" },
+ { id: "checkout_conversion", name: "Checkout conversion", kind: "binomial", direction: null },
+ { id: "checkout_latency_p95", name: "Checkout latency p95", kind: "count", direction: null },
];
}
diff --git a/apps/control-panel/src/lib/experiments/metric-comparison-rows.ts b/apps/control-panel/src/lib/experiments/metric-comparison-rows.ts
index 3d233321..8b8722b0 100644
--- a/apps/control-panel/src/lib/experiments/metric-comparison-rows.ts
+++ b/apps/control-panel/src/lib/experiments/metric-comparison-rows.ts
@@ -20,8 +20,7 @@ import { type MetricNames, metricDisplayName, metricNamesById } from "./metric-n
* arrive computed.
*/
-export type ComparisonMetric = Pick &
- Partial>;
+export type ComparisonMetric = Pick;
export type MetricComparisonRole = "decision" | "guardrail" | "exploratory";
diff --git a/apps/marketing/src/docs/markdown-route.test.ts b/apps/marketing/src/docs/markdown-route.test.ts
index 72b7ec6d..31d7be80 100644
--- a/apps/marketing/src/docs/markdown-route.test.ts
+++ b/apps/marketing/src/docs/markdown-route.test.ts
@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import { quickstartMarkdown } from "./markdown";
-import { markdownForPath, staticMarkdownPaths } from "./markdown-route";
-import { staticPagePaths } from "./sitemap";
+import { markdownForPath } from "./markdown-route";
+import { canonicalPageUrls, staticPagePaths } from "./sitemap";
function markdownUrlForPage(path: string): string {
if (path === "/") return "/.md";
@@ -32,16 +32,14 @@ describe("markdownForPath", () => {
expect(markdown).toMatch(/^# Zero to a resolving Flag/m);
});
- it("serves the .md suffix for every static HTML page, including top-level ones", () => {
- const topLevelHtmlPages = staticPagePaths.filter((path) => !path.startsWith("/docs"));
- expect(topLevelHtmlPages).toEqual(["/", "/quickstart"]);
- expect(staticMarkdownPaths).toContain("/quickstart");
- expect(staticMarkdownPaths.filter((path) => !path.startsWith("/docs"))).toEqual([
- "/",
- "/quickstart",
- ]);
+ it("serves the .md suffix for every canonical HTML page, including top-level ones", () => {
+ // The Worker answers `.md` before the router runs, so this is the
+ // only guard that a new page ships with its markdown twin.
+ const pages = canonicalPageUrls.map((href) => new URL(href).pathname);
+ expect(pages.filter((path) => !path.startsWith("/docs"))).toEqual(["/", "/quickstart"]);
+ expect(pages.length).toBeGreaterThan(staticPagePaths.length);
- for (const path of staticMarkdownPaths) {
+ for (const path of pages) {
const markdown = markdownForPath(path);
expect(markdown, path).not.toBeNull();
expect(markdownForPath(markdownUrlForPage(path)), markdownUrlForPage(path)).toBe(markdown);
diff --git a/apps/marketing/src/docs/markdown-route.ts b/apps/marketing/src/docs/markdown-route.ts
index e5d70c0d..9e42920c 100644
--- a/apps/marketing/src/docs/markdown-route.ts
+++ b/apps/marketing/src/docs/markdown-route.ts
@@ -23,8 +23,6 @@ const staticMarkdown = new Map string>([
["/docs/errors", errorIndexMarkdown],
]);
-export const staticMarkdownPaths = [...staticMarkdown.keys()] as const;
-
export function markdownForPath(pathname: string): string | null {
const documentPath = htmlPathForMarkdownUrl(pathname);
const staticDocument = staticMarkdown.get(documentPath);
diff --git a/apps/marketing/src/routeTree.gen.ts b/apps/marketing/src/routeTree.gen.ts
index 82cc80b2..1a323689 100644
--- a/apps/marketing/src/routeTree.gen.ts
+++ b/apps/marketing/src/routeTree.gen.ts
@@ -13,19 +13,14 @@ import { Route as IndexRouteImport } from './routes/index'
import { Route as HealthRouteImport } from './routes/health'
import { Route as LlmsDottxtRouteImport } from './routes/llms[.]txt'
import { Route as QuickstartRouteImport } from './routes/quickstart'
-import { Route as QuickstartDotmdRouteImport } from './routes/quickstart[.]md'
import { Route as RobotsDottxtRouteImport } from './routes/robots[.]txt'
import { Route as SitemapDotxmlRouteImport } from './routes/sitemap[.]xml'
import { Route as DotwellKnownApiCatalogRouteImport } from './routes/[.]well-known.api-catalog'
import { Route as DocsIndexRouteImport } from './routes/docs.index'
import { Route as DocsCliRouteImport } from './routes/docs.cli'
-import { Route as DocsCliDotmdRouteImport } from './routes/docs.cli[.]md'
import { Route as DocsCodeAgentsRouteImport } from './routes/docs.code-agents'
-import { Route as DocsCodeAgentsDotmdRouteImport } from './routes/docs.code-agents[.]md'
import { Route as DocsErrorsRouteImport } from './routes/docs.errors'
-import { Route as DocsErrorsDotmdRouteImport } from './routes/docs.errors[.]md'
import { Route as DocsFlagsRouteImport } from './routes/docs.flags'
-import { Route as DocsFlagsDotmdRouteImport } from './routes/docs.flags[.]md'
import { Route as DocsErrorCodeRouteImport } from './routes/docs.error.$code'
import { Route as DocsSdkTopicRouteImport } from './routes/docs.sdk.$topic'
@@ -49,11 +44,6 @@ const QuickstartRoute = QuickstartRouteImport.update({
path: '/quickstart',
getParentRoute: () => rootRouteImport,
} as any)
-const QuickstartDotmdRoute = QuickstartDotmdRouteImport.update({
- id: '/quickstart.md',
- path: '/quickstart.md',
- getParentRoute: () => rootRouteImport,
-} as any)
const RobotsDottxtRoute = RobotsDottxtRouteImport.update({
id: '/robots.txt',
path: '/robots.txt',
@@ -79,41 +69,21 @@ const DocsCliRoute = DocsCliRouteImport.update({
path: '/docs/cli',
getParentRoute: () => rootRouteImport,
} as any)
-const DocsCliDotmdRoute = DocsCliDotmdRouteImport.update({
- id: '/docs/cli.md',
- path: '/docs/cli.md',
- getParentRoute: () => rootRouteImport,
-} as any)
const DocsCodeAgentsRoute = DocsCodeAgentsRouteImport.update({
id: '/docs/code-agents',
path: '/docs/code-agents',
getParentRoute: () => rootRouteImport,
} as any)
-const DocsCodeAgentsDotmdRoute = DocsCodeAgentsDotmdRouteImport.update({
- id: '/docs/code-agents.md',
- path: '/docs/code-agents.md',
- getParentRoute: () => rootRouteImport,
-} as any)
const DocsErrorsRoute = DocsErrorsRouteImport.update({
id: '/docs/errors',
path: '/docs/errors',
getParentRoute: () => rootRouteImport,
} as any)
-const DocsErrorsDotmdRoute = DocsErrorsDotmdRouteImport.update({
- id: '/docs/errors.md',
- path: '/docs/errors.md',
- getParentRoute: () => rootRouteImport,
-} as any)
const DocsFlagsRoute = DocsFlagsRouteImport.update({
id: '/docs/flags',
path: '/docs/flags',
getParentRoute: () => rootRouteImport,
} as any)
-const DocsFlagsDotmdRoute = DocsFlagsDotmdRouteImport.update({
- id: '/docs/flags.md',
- path: '/docs/flags.md',
- getParentRoute: () => rootRouteImport,
-} as any)
const DocsErrorCodeRoute = DocsErrorCodeRouteImport.update({
id: '/docs/error/$code',
path: '/docs/error/$code',
@@ -130,18 +100,13 @@ export interface FileRoutesByFullPath {
'/health': typeof HealthRoute
'/llms.txt': typeof LlmsDottxtRoute
'/quickstart': typeof QuickstartRoute
- '/quickstart.md': typeof QuickstartDotmdRoute
'/robots.txt': typeof RobotsDottxtRoute
'/sitemap.xml': typeof SitemapDotxmlRoute
'/.well-known/api-catalog': typeof DotwellKnownApiCatalogRoute
'/docs/cli': typeof DocsCliRoute
- '/docs/cli.md': typeof DocsCliDotmdRoute
'/docs/code-agents': typeof DocsCodeAgentsRoute
- '/docs/code-agents.md': typeof DocsCodeAgentsDotmdRoute
'/docs/errors': typeof DocsErrorsRoute
- '/docs/errors.md': typeof DocsErrorsDotmdRoute
'/docs/flags': typeof DocsFlagsRoute
- '/docs/flags.md': typeof DocsFlagsDotmdRoute
'/docs/': typeof DocsIndexRoute
'/docs/error/$code': typeof DocsErrorCodeRoute
'/docs/sdk/$topic': typeof DocsSdkTopicRoute
@@ -151,18 +116,13 @@ export interface FileRoutesByTo {
'/health': typeof HealthRoute
'/llms.txt': typeof LlmsDottxtRoute
'/quickstart': typeof QuickstartRoute
- '/quickstart.md': typeof QuickstartDotmdRoute
'/robots.txt': typeof RobotsDottxtRoute
'/sitemap.xml': typeof SitemapDotxmlRoute
'/.well-known/api-catalog': typeof DotwellKnownApiCatalogRoute
'/docs/cli': typeof DocsCliRoute
- '/docs/cli.md': typeof DocsCliDotmdRoute
'/docs/code-agents': typeof DocsCodeAgentsRoute
- '/docs/code-agents.md': typeof DocsCodeAgentsDotmdRoute
'/docs/errors': typeof DocsErrorsRoute
- '/docs/errors.md': typeof DocsErrorsDotmdRoute
'/docs/flags': typeof DocsFlagsRoute
- '/docs/flags.md': typeof DocsFlagsDotmdRoute
'/docs': typeof DocsIndexRoute
'/docs/error/$code': typeof DocsErrorCodeRoute
'/docs/sdk/$topic': typeof DocsSdkTopicRoute
@@ -173,18 +133,13 @@ export interface FileRoutesById {
'/health': typeof HealthRoute
'/llms.txt': typeof LlmsDottxtRoute
'/quickstart': typeof QuickstartRoute
- '/quickstart.md': typeof QuickstartDotmdRoute
'/robots.txt': typeof RobotsDottxtRoute
'/sitemap.xml': typeof SitemapDotxmlRoute
'/.well-known/api-catalog': typeof DotwellKnownApiCatalogRoute
'/docs/cli': typeof DocsCliRoute
- '/docs/cli.md': typeof DocsCliDotmdRoute
'/docs/code-agents': typeof DocsCodeAgentsRoute
- '/docs/code-agents.md': typeof DocsCodeAgentsDotmdRoute
'/docs/errors': typeof DocsErrorsRoute
- '/docs/errors.md': typeof DocsErrorsDotmdRoute
'/docs/flags': typeof DocsFlagsRoute
- '/docs/flags.md': typeof DocsFlagsDotmdRoute
'/docs/': typeof DocsIndexRoute
'/docs/error/$code': typeof DocsErrorCodeRoute
'/docs/sdk/$topic': typeof DocsSdkTopicRoute
@@ -196,18 +151,13 @@ export interface FileRouteTypes {
| '/health'
| '/llms.txt'
| '/quickstart'
- | '/quickstart.md'
| '/robots.txt'
| '/sitemap.xml'
| '/.well-known/api-catalog'
| '/docs/cli'
- | '/docs/cli.md'
| '/docs/code-agents'
- | '/docs/code-agents.md'
| '/docs/errors'
- | '/docs/errors.md'
| '/docs/flags'
- | '/docs/flags.md'
| '/docs/'
| '/docs/error/$code'
| '/docs/sdk/$topic'
@@ -217,18 +167,13 @@ export interface FileRouteTypes {
| '/health'
| '/llms.txt'
| '/quickstart'
- | '/quickstart.md'
| '/robots.txt'
| '/sitemap.xml'
| '/.well-known/api-catalog'
| '/docs/cli'
- | '/docs/cli.md'
| '/docs/code-agents'
- | '/docs/code-agents.md'
| '/docs/errors'
- | '/docs/errors.md'
| '/docs/flags'
- | '/docs/flags.md'
| '/docs'
| '/docs/error/$code'
| '/docs/sdk/$topic'
@@ -238,18 +183,13 @@ export interface FileRouteTypes {
| '/health'
| '/llms.txt'
| '/quickstart'
- | '/quickstart.md'
| '/robots.txt'
| '/sitemap.xml'
| '/.well-known/api-catalog'
| '/docs/cli'
- | '/docs/cli.md'
| '/docs/code-agents'
- | '/docs/code-agents.md'
| '/docs/errors'
- | '/docs/errors.md'
| '/docs/flags'
- | '/docs/flags.md'
| '/docs/'
| '/docs/error/$code'
| '/docs/sdk/$topic'
@@ -260,18 +200,13 @@ export interface RootRouteChildren {
HealthRoute: typeof HealthRoute
LlmsDottxtRoute: typeof LlmsDottxtRoute
QuickstartRoute: typeof QuickstartRoute
- QuickstartDotmdRoute: typeof QuickstartDotmdRoute
RobotsDottxtRoute: typeof RobotsDottxtRoute
SitemapDotxmlRoute: typeof SitemapDotxmlRoute
DotwellKnownApiCatalogRoute: typeof DotwellKnownApiCatalogRoute
DocsCliRoute: typeof DocsCliRoute
- DocsCliDotmdRoute: typeof DocsCliDotmdRoute
DocsCodeAgentsRoute: typeof DocsCodeAgentsRoute
- DocsCodeAgentsDotmdRoute: typeof DocsCodeAgentsDotmdRoute
DocsErrorsRoute: typeof DocsErrorsRoute
- DocsErrorsDotmdRoute: typeof DocsErrorsDotmdRoute
DocsFlagsRoute: typeof DocsFlagsRoute
- DocsFlagsDotmdRoute: typeof DocsFlagsDotmdRoute
DocsIndexRoute: typeof DocsIndexRoute
DocsErrorCodeRoute: typeof DocsErrorCodeRoute
DocsSdkTopicRoute: typeof DocsSdkTopicRoute
@@ -307,13 +242,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof QuickstartRouteImport
parentRoute: typeof rootRouteImport
}
- '/quickstart.md': {
- id: '/quickstart.md'
- path: '/quickstart.md'
- fullPath: '/quickstart.md'
- preLoaderRoute: typeof QuickstartDotmdRouteImport
- parentRoute: typeof rootRouteImport
- }
'/robots.txt': {
id: '/robots.txt'
path: '/robots.txt'
@@ -349,13 +277,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DocsCliRouteImport
parentRoute: typeof rootRouteImport
}
- '/docs/cli.md': {
- id: '/docs/cli.md'
- path: '/docs/cli.md'
- fullPath: '/docs/cli.md'
- preLoaderRoute: typeof DocsCliDotmdRouteImport
- parentRoute: typeof rootRouteImport
- }
'/docs/code-agents': {
id: '/docs/code-agents'
path: '/docs/code-agents'
@@ -363,13 +284,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DocsCodeAgentsRouteImport
parentRoute: typeof rootRouteImport
}
- '/docs/code-agents.md': {
- id: '/docs/code-agents.md'
- path: '/docs/code-agents.md'
- fullPath: '/docs/code-agents.md'
- preLoaderRoute: typeof DocsCodeAgentsDotmdRouteImport
- parentRoute: typeof rootRouteImport
- }
'/docs/errors': {
id: '/docs/errors'
path: '/docs/errors'
@@ -377,13 +291,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DocsErrorsRouteImport
parentRoute: typeof rootRouteImport
}
- '/docs/errors.md': {
- id: '/docs/errors.md'
- path: '/docs/errors.md'
- fullPath: '/docs/errors.md'
- preLoaderRoute: typeof DocsErrorsDotmdRouteImport
- parentRoute: typeof rootRouteImport
- }
'/docs/flags': {
id: '/docs/flags'
path: '/docs/flags'
@@ -391,13 +298,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DocsFlagsRouteImport
parentRoute: typeof rootRouteImport
}
- '/docs/flags.md': {
- id: '/docs/flags.md'
- path: '/docs/flags.md'
- fullPath: '/docs/flags.md'
- preLoaderRoute: typeof DocsFlagsDotmdRouteImport
- parentRoute: typeof rootRouteImport
- }
'/docs/error/$code': {
id: '/docs/error/$code'
path: '/docs/error/$code'
@@ -420,18 +320,13 @@ const rootRouteChildren: RootRouteChildren = {
HealthRoute: HealthRoute,
LlmsDottxtRoute: LlmsDottxtRoute,
QuickstartRoute: QuickstartRoute,
- QuickstartDotmdRoute: QuickstartDotmdRoute,
RobotsDottxtRoute: RobotsDottxtRoute,
SitemapDotxmlRoute: SitemapDotxmlRoute,
DotwellKnownApiCatalogRoute: DotwellKnownApiCatalogRoute,
DocsCliRoute: DocsCliRoute,
- DocsCliDotmdRoute: DocsCliDotmdRoute,
DocsCodeAgentsRoute: DocsCodeAgentsRoute,
- DocsCodeAgentsDotmdRoute: DocsCodeAgentsDotmdRoute,
DocsErrorsRoute: DocsErrorsRoute,
- DocsErrorsDotmdRoute: DocsErrorsDotmdRoute,
DocsFlagsRoute: DocsFlagsRoute,
- DocsFlagsDotmdRoute: DocsFlagsDotmdRoute,
DocsIndexRoute: DocsIndexRoute,
DocsErrorCodeRoute: DocsErrorCodeRoute,
DocsSdkTopicRoute: DocsSdkTopicRoute,
diff --git a/apps/marketing/src/routes/docs.cli[.]md.ts b/apps/marketing/src/routes/docs.cli[.]md.ts
deleted file mode 100644
index 6853c44f..00000000
--- a/apps/marketing/src/routes/docs.cli[.]md.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { cliDocMarkdown } from "../docs/markdown";
-import { markdownResponse } from "../docs/serve-markdown";
-
-export const Route = createFileRoute("/docs/cli.md")({
- server: {
- handlers: {
- GET: async () => markdownResponse(cliDocMarkdown()),
- },
- },
-});
diff --git a/apps/marketing/src/routes/docs.code-agents[.]md.ts b/apps/marketing/src/routes/docs.code-agents[.]md.ts
deleted file mode 100644
index b82e432a..00000000
--- a/apps/marketing/src/routes/docs.code-agents[.]md.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { codeAgentsDocMarkdown } from "../docs/markdown";
-import { markdownResponse } from "../docs/serve-markdown";
-
-export const Route = createFileRoute("/docs/code-agents.md")({
- server: {
- handlers: {
- GET: async () => markdownResponse(codeAgentsDocMarkdown()),
- },
- },
-});
diff --git a/apps/marketing/src/routes/docs.errors[.]md.ts b/apps/marketing/src/routes/docs.errors[.]md.ts
deleted file mode 100644
index 8c1054f1..00000000
--- a/apps/marketing/src/routes/docs.errors[.]md.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { errorIndexMarkdown } from "../docs/markdown";
-import { markdownResponse } from "../docs/serve-markdown";
-
-export const Route = createFileRoute("/docs/errors.md")({
- server: {
- handlers: {
- GET: async () => markdownResponse(errorIndexMarkdown()),
- },
- },
-});
diff --git a/apps/marketing/src/routes/docs.flags[.]md.ts b/apps/marketing/src/routes/docs.flags[.]md.ts
deleted file mode 100644
index 72880e2f..00000000
--- a/apps/marketing/src/routes/docs.flags[.]md.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { flagsDocMarkdown } from "../docs/markdown";
-import { markdownResponse } from "../docs/serve-markdown";
-
-export const Route = createFileRoute("/docs/flags.md")({
- server: {
- handlers: {
- GET: async () => markdownResponse(flagsDocMarkdown()),
- },
- },
-});
diff --git a/apps/marketing/src/routes/quickstart[.]md.ts b/apps/marketing/src/routes/quickstart[.]md.ts
deleted file mode 100644
index c8753347..00000000
--- a/apps/marketing/src/routes/quickstart[.]md.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createFileRoute } from "@tanstack/react-router";
-import { quickstartMarkdown } from "../docs/markdown";
-import { markdownResponse } from "../docs/serve-markdown";
-
-export const Route = createFileRoute("/quickstart.md")({
- server: {
- handlers: {
- GET: async () => markdownResponse(quickstartMarkdown()),
- },
- },
-});
diff --git a/scripts/docs-link-lint.mjs b/scripts/docs-link-lint.mjs
index a4d88408..13190510 100644
--- a/scripts/docs-link-lint.mjs
+++ b/scripts/docs-link-lint.mjs
@@ -135,19 +135,19 @@ export function lintPublishedDocsText(filePath, text, inventory) {
function violationForPublishedUrl(url, inventory) {
const pathname = normalizePathname(decodeURIComponent(url.pathname));
- const route = routeForPath(inventory, pathname);
+ // The Worker serves `.md` for every page, so a markdown URL is valid
+ // exactly when its HTML page is a route. There are no markdown file routes.
+ const pagePath = pathname.endsWith(".md") ? pathname.slice(0, -3) : pathname;
+ const route = routeForPath(inventory, pagePath);
if (!route) return `${url.href} names no marketing route.`;
- if (pathname.endsWith(".md") && !routeForPath(inventory, pathname.slice(0, -3))) {
- return `${url.href} has no HTML twin.`;
- }
const anchor = decodeURIComponent(url.hash.slice(1));
if (!anchor) return undefined;
- const routedAlternative = `${pathname === "/" ? "" : pathname}/${anchor}`;
+ const routedAlternative = `${pagePath === "/" ? "" : pagePath}/${anchor}`;
if (hasStaticRoute(inventory, routedAlternative)) {
return `${url.href} is stale; ${origin}${routedAlternative} is a route, not a section link.`;
}
- if (!route.anchors.has(anchor)) return `${url.href} names no section anchor on ${pathname}.`;
+ if (!route.anchors.has(anchor)) return `${url.href} names no section anchor on ${pagePath}.`;
return undefined;
}
diff --git a/scripts/docs-link-lint.test.mjs b/scripts/docs-link-lint.test.mjs
index 4869e52d..89c9f3ea 100644
--- a/scripts/docs-link-lint.test.mjs
+++ b/scripts/docs-link-lint.test.mjs
@@ -20,7 +20,6 @@ async function fixtureRoutes(t) {
'createFileRoute("/docs/")({});\n',
),
writeFile(path.join(routes, "docs.errors.tsx"), 'createFileRoute("/docs/errors")({});'),
- writeFile(path.join(routes, "docs.errors[.]md.ts"), 'createFileRoute("/docs/errors.md")({});'),
writeFile(
path.join(routes, "docs.error.$code.tsx"),
'createFileRoute("/docs/error/$code")({});',
@@ -63,14 +62,14 @@ test("rejects a route-side mutation that removes a published target", async (t)
);
});
-test("rejects markdown routes without an HTML twin", async (t) => {
+test("rejects a markdown URL whose HTML page is not a route", async (t) => {
const routes = await fixtureRoutes(t);
await rm(path.join(routes, "docs.errors.tsx"));
const inventory = await buildRouteInventory(routes);
assert.match(
lintPublishedDocsText("README.md", `${origin}/docs/errors.md`, inventory)[0].message,
- /has no HTML twin/,
+ /names no marketing route/,
);
});
@@ -84,4 +83,8 @@ test("rejects missing anchors and stale fragment collisions", async (t) => {
/names no section anchor/,
);
assert.match(lintPublishedDocsText("README.md", movedCatalog, inventory)[0].message, /is stale/);
+ assert.match(
+ lintPublishedDocsText("README.md", `${origin}/docs.md#${"errors"}`, inventory)[0].message,
+ /is stale/,
+ );
});