From 7caba977ef0607d819ee3b1476ed2ecd10af5be7 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Fri, 25 Oct 2024 19:34:09 -0700 Subject: [PATCH] preserveIndex, preserveExtension --- docs/config.md | 8 ++++-- docs/getting-started.md | 2 +- src/config.ts | 25 +++++++++++++------ src/preview.ts | 4 +-- templates/default/observablehq.config.js.tmpl | 3 ++- templates/empty/observablehq.config.js.tmpl | 3 ++- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/docs/config.md b/docs/config.md index afac78a27..960bad819 100644 --- a/docs/config.md +++ b/docs/config.md @@ -197,9 +197,13 @@ footer: ({path}) => ` +## preserveIndex -Whether page links should be “clean”, _i.e._, formatted without a `.html` extension. Defaults to true. If true, a link to `config.html` will be formatted as `config`. Regardless of this setting, a link to an index page will drop the implied `index.html`; for example `foo/index.html` will be formatted as `foo/`. +Whether page links should preserve `/index` for directories. Defaults to false. If true, a link to `/` will be formatted as `/index` if the **preserveExtension** option is false or `/index.html` if the **preserveExtension** option is true. + +## preserveExtension + +Whether page links should preserve the `.html` extension. Defaults to false. If true, a link to `/foo` will be formatted as `/foo.html`. ## toc diff --git a/docs/getting-started.md b/docs/getting-started.md index 9587bec7f..ede7d4390 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -535,7 +535,7 @@ The build command generates the `dist` directory; you can then copy
npx http-server dist
-
By default, Framework generates “clean” URLs by dropping the `.html` extension from page links. Not all webhosts support this; some need the cleanUrls config option set to false.
+
By default, Framework generates “clean” URLs by dropping the `.html` extension from page links. Not all webhosts support this; some need the preserveExtension config option set to true.
When deploying to GitHub Pages without using GitHub’s related actions (configure-pages, deploy-pages, and diff --git a/src/config.ts b/src/config.ts index 126445a90..323577587 100644 --- a/src/config.ts +++ b/src/config.ts @@ -124,6 +124,8 @@ export interface ConfigSpec { typographer?: unknown; quotes?: unknown; cleanUrls?: unknown; + preserveIndex?: unknown; + preserveExtension?: unknown; markdownIt?: unknown; } @@ -259,7 +261,7 @@ export function normalizeConfig(spec: ConfigSpec = {}, defaultRoot?: string, wat const footer = pageFragment(spec.footer === undefined ? defaultFooter() : spec.footer); const search = spec.search == null || spec.search === false ? null : normalizeSearch(spec.search as any); const interpreters = normalizeInterpreters(spec.interpreters as any); - const normalizePath = getPathNormalizer(spec.cleanUrls); + const normalizePath = getPathNormalizer(spec); // If this path ends with a slash, then add an implicit /index to the // end of the path. Otherwise, remove the .html extension (we use clean @@ -324,13 +326,22 @@ function normalizeDynamicPaths(spec: unknown): Config["paths"] { return async function* () { yield* paths; }; // prettier-ignore } -function getPathNormalizer(spec: unknown = true): (path: string) => string { - const cleanUrls = Boolean(spec); +function normalizeCleanUrls(spec: unknown): boolean { + console.warn(`${yellow("Warning:")} the ${bold("cleanUrls")} option is deprecated; use ${bold("preserveIndex")} and ${bold("preserveExtension")} instead.`); // prettier-ignore + return !spec; +} + +function getPathNormalizer(spec: ConfigSpec): (path: string) => string { + const preserveIndex = spec.preserveIndex !== undefined ? Boolean(spec.preserveIndex) : false; + const preserveExtension = spec.preserveExtension !== undefined ? Boolean(spec.preserveExtension) : spec.cleanUrls !== undefined ? normalizeCleanUrls(spec.cleanUrls) : false; // prettier-ignore return (path) => { - if (path && !path.endsWith("/") && !extname(path)) path += ".html"; - if (path === "index.html") path = "."; - else if (path.endsWith("/index.html")) path = path.slice(0, -"index.html".length); - else if (cleanUrls) path = path.replace(/\.html$/, ""); + const ext = extname(path); + if (path.endsWith(".")) path += "/"; + if (ext === ".html") path = path.slice(0, -".html".length); + if (path.endsWith("/index")) path = path.slice(0, -"index".length); + if (preserveIndex && path.endsWith("/")) path += "index"; + if (!preserveIndex && path === "index") path = "."; + if (preserveExtension && path && !path.endsWith(".") && !path.endsWith("/") && !extname(path)) path += ".html"; return path; }; } diff --git a/src/preview.ts b/src/preview.ts index 42f3c931a..21a90f7c7 100644 --- a/src/preview.ts +++ b/src/preview.ts @@ -176,8 +176,8 @@ export class PreviewServer { } else { if ((pathname = normalize(pathname)).startsWith("..")) throw new Error("Invalid path: " + pathname); - // Normalize the pathname (e.g., adding ".html" if cleanUrls is false, - // dropping ".html" if cleanUrls is true) and redirect if necessary. + // Normalize the pathname (e.g., adding ".html" or removing ".html" + // based on preserveExtension) and redirect if necessary. const normalizedPathname = encodeURI(config.normalizePath(pathname)); if (url.pathname !== normalizedPathname) { res.writeHead(302, {Location: normalizedPathname + url.search}); diff --git a/templates/default/observablehq.config.js.tmpl b/templates/default/observablehq.config.js.tmpl index bfa5ef704..21c860028 100644 --- a/templates/default/observablehq.config.js.tmpl +++ b/templates/default/observablehq.config.js.tmpl @@ -33,5 +33,6 @@ export default { // search: true, // activate search // linkify: true, // convert URLs in Markdown to links // typographer: false, // smart quotes and other typographic improvements - // cleanUrls: true, // drop .html from URLs + // preserveExtension: false, // drop .html from URLs + // preserveIndex: false, // drop /index from URLs }; diff --git a/templates/empty/observablehq.config.js.tmpl b/templates/empty/observablehq.config.js.tmpl index bfa5ef704..21c860028 100644 --- a/templates/empty/observablehq.config.js.tmpl +++ b/templates/empty/observablehq.config.js.tmpl @@ -33,5 +33,6 @@ export default { // search: true, // activate search // linkify: true, // convert URLs in Markdown to links // typographer: false, // smart quotes and other typographic improvements - // cleanUrls: true, // drop .html from URLs + // preserveExtension: false, // drop .html from URLs + // preserveIndex: false, // drop /index from URLs };