Skip to content

Commit

Permalink
preserveIndex, preserveExtension
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Oct 26, 2024
1 parent 031ac6d commit 7caba97
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 14 deletions.
8 changes: 6 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ footer: ({path}) => `<a href="https://github.com/example/test/blob/main/src${pat

The base path when serving the site. Currently this only affects the custom 404 page, if any.

## cleanUrls <a href="https://github.com/observablehq/framework/releases/tag/v1.3.0" class="observablehq-version-badge" data-version="^1.3.0" title="Added in 1.3.0"></a>
## preserveIndex <a href="https://github.com/observablehq/framework/pulls/1784" class="observablehq-version-badge" data-version="prerelease" title="Added in #1784"></a>

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 <a href="https://github.com/observablehq/framework/pulls/1784" class="observablehq-version-badge" data-version="prerelease" title="Added in #1784"></a>

Whether page links should preserve the `.html` extension. Defaults to false. If true, a link to `/foo` will be formatted as `/foo.html`.

## toc

Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ The <code>build</code> command generates the `dist` directory; you can then copy

<pre data-copy>npx http-server dist</pre>

<div class="tip">By default, Framework generates “clean” URLs by dropping the `.html` extension from page links. Not all webhosts support this; some need the <a href="./config#clean-urls"><b>cleanUrls</b> config option</a> set to false.</div>
<div class="tip">By default, Framework generates “clean” URLs by dropping the `.html` extension from page links. Not all webhosts support this; some need the <a href="./config#preserve-extension"><b>preserveExtension</b> config option</a> set to true.</div>

<div class="tip">When deploying to GitHub Pages without using GitHub’s related actions (<a href="https://github.com/actions/configure-pages">configure-pages</a>,
<a href="https://github.com/actions/deploy-pages">deploy-pages</a>, and
Expand Down
25 changes: 18 additions & 7 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ export interface ConfigSpec {
typographer?: unknown;
quotes?: unknown;
cleanUrls?: unknown;
preserveIndex?: unknown;
preserveExtension?: unknown;
markdownIt?: unknown;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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});
Expand Down
3 changes: 2 additions & 1 deletion templates/default/observablehq.config.js.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
3 changes: 2 additions & 1 deletion templates/empty/observablehq.config.js.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

0 comments on commit 7caba97

Please sign in to comment.